Welcome to MSDN Blogs Sign in | Join | Help

TR1 Slide Decks

Hi, I'm Stephan, the Visual C++ Libraries Developer working on TR1.

 

Recently, I gave 3 presentations within Microsoft about the most novel components of TR1: shared_ptr, regex, and the additions to <functional> (including mem_fn(), bind(), and tr1::function).  These presentations explained where to use, how to use, and how to avoid misusing these components, with plenty of examples.

 

Attached at the end of this post is a ZIP of the slide decks for each of the presentations, in PowerPoint 2007 format.

 

Each slide deck mostly stands alone, although the "shared_ptr To Noncopyable" and "shared_ptr To Polymorphic" examples require some context and additional explanation:

 

The "shared_ptr To Noncopyable" example demonstrates how to create a container of noncopyable resource managers.  A resource is something that must be acquired from the system and then released afterwards.  The most common resource is memory (acquired in C++ with new, and released with delete), but there are many non-memory resources, such as files, sockets, textures, fonts, and so forth.  A resource manager is an object that encapsulates a resource, controlling its lifetime and permitting access to it.  Resource managers acquire resources in their constructors, and release resources in their destructors (this is the somewhat-mysteriously-named RAII principle: Resource Acquisition Is Initialization, implying RRID: Resource Release Is Destruction).  std::vector is an example of a resource manager for memory, while std::ifstream is an example of a resource manager for files.  Memory resource managers are usually copyable (and assignable); chunks of memory can easily be copied and assigned.  But non-memory resource managers are usually noncopyable (and nonassignable); either their underlying resources can't be copied without additional information (e.g. copying a file requires a new name), or copying them is a relatively expensive operation (e.g. textures consume precious video card memory, etc.).  So, it's best to prohibit copy construction and copy assignment of non-memory resource managers.  This requires programmers to explicitly copy the underlying resources when that's desired.

 

The problem here is that STL (and TR1) containers require ordinary value types.  An ordinary value type is "something that behaves like an int"; ints are copyable and assignable.  vectors copy their contained elements when undergoing reallocation, and so forth.  You can't have a vector<ifstream> because ifstream is noncopyable.  But sometimes, that's exactly what you want.

 

In this example (admittedly somewhat contrived), I'm writing a program to interleave text files.  The user will have an arbitrary number of text files, and will provide the names of the files to the program.  Then, the program will have to loop through the files in order, printing out the first line of each file, then the second line, and so forth.  When a text file runs out of lines (they can have different numbers of lines), the program has to start skipping that file.  When all the lines from all the files have been printed, the program has to stop.

 

Now, I could write this by reading each file into a vector<string> (storing each line), and building up a vector<vector<string> > (storing each file), and then looping through that.  But that would require reading everything into memory.  Suppose I don't want to do that.

 

Well, if I could use a vector<ifstream>, I could repeatedly loop through the vector, reading one line from each file in turn.  When a file ran out of lines, I could remove it from the vector.  But ifstream is noncopyable.

 

To solve this, I can use shared_ptr.  shared_ptr can be used as a handle to a noncopyable object; the shared_ptr itself is copyable and assignable.

 

Slide 1/3 of the example shows the contents of 3 text files.

 

Slide 2/3 shows the code.  To fit the code onto a single slide, I use a queue<shared_ptr<ifstream> >.  I begin by reading filenames from cin (with the for-loop).  From each filename, I new up an ifstream, held by shared_ptr, and push it into the queue.  At the end of this for-loop, the queue contains shared_ptrs to the files mentioned by the user in order.

 

Then, I loop through the queue (with the while-loop) as long as it contains files to process.  I attempt to read a line from the file at the front of the queue (this is the next file to process).  If that's successful (the file still contains lines), I print it out.  I want to keep working on that file, so I push() a copy of the shared_ptr to this file (q.front()), to the back of the queue.  Then I pop() the front of the queue.  (At this point, particularly attentive readers should ask whether q.push(q.front()) raises the specter of iterator invalidation; the answer is that it does not.  I would have avoided this in the interests of clarity, but it would have taken more lines.)  If I wasn't able to read a line from the file, then it's empty, so I simply want to pop it from the front of the queue.  Then I continue with the loop.

 

Slide 3/3 shows the filenames being entered, and the program's output.

 

The "shared_ptr To Polymorphic" example demonstrates how to create a container of polymorphic objects (i.e. classes with virtual functions).  Polymorphic objects should always be noncopyable, because of the danger of slicing.  Inheritance means substitutability; a Derived object has to be usable wherever a Base object would be usable.  However, copying presents a problem.  If Base is copyable, then you can copy from a Base to a Base.  But substitutability then implies that you can copy from a Derived (which is a Base) to a Base.  This "slices" off any Derived behavior and state, which is almost always undesirable.  Therefore, copy construction and copy assignment of polymorphic base classes should be prohibited.  (You should provide a virtual clone() function if you need to copy polymorphic objects safely.)

 

If Base is noncopyable, you can't have a vector<Base>.  You could try to use a vector<Base *>, newing up Derived objects and storing pointers to them, but that would be highly likely to leak, especially in the presence of exceptions.  As with resource managers, shared_ptr allows us to manipulate noncopyable objects with copyable handles.  vector<shared_ptr<Base> > is a powerful construct that can be used in many situations.

 

In this example (even more contrived; you can mentally substitute your favorite Base and Derived classes), I have a polymorphic base class Animal.  Therefore, it has a virtual destructor, no copy constructor, and no copy assignment operator.  It stores a string m_name (the name of the Animal), and has an explicit constructor taking that name.  Animal uses the Non-Virtual Inheritance idiom, so it has a public, non-virtual member function named noise(), which returns "<name> says <something>".  The "something" is customizable by derived classes, through the private pure virtual member function noise_impl().  (Yes, private virtual member functions can be overridden; the difference is that derived classes cannot call the base implementation, whereas they could if the base implementation were protected.  As noise_impl() is pure, there is no base implementation, so the difference is theoretical - but I prefer to lock down access control unless I need looser control.)

 

Slide 2/4 shows three derived classes, Cat, Dog, and Pig, identical in structure except for what their noise_impl()s return.

 

Slide 3/4 constructs a vector<shared_ptr<Animal> >, which is then filled with a Cat, Dog, and Pig.  Then I print out the noises that each Animal makes.  I use the STL algorithm transform() on the vector, printing strings to cout separated by newlines.  mem_fn(&Animal::noise) uses tr1::mem_fn() to adapt a pointer-to-member-function (&Animal::noise) to a function-object (what transform() wants).

 

Slide 4/4 shows the output, demonstrating that the virtual function calls worked as usual.

 

The point of these two examples is that shared_ptr is useful for much more than sharing and exception safety.  shared_ptr allows you to use the STL in more situations, by wrapping noncopyable objects in copyable clothing.

 

If you have any questions, I'll be happy to answer them in the Comments!

 

Stephan T. Lavavej

 

Published Friday, February 22, 2008 10:53 AM by vcblog

Attachment(s): TR1 Presentations.zip

Comments

Friday, February 22, 2008 3:25 PM by BioSensorAB » TR1 Slide Decks

# BioSensorAB &raquo; TR1 Slide Decks

Friday, February 22, 2008 7:21 PM by Sohail

# re: TR1 Slide Decks

Please tell me that you were presenting this to C# developers and not C++ developers. Anyone who needs an introduction to these concepts should be smacked upside the head! All these "additions" have been around for years in Boost.

Friday, February 22, 2008 7:51 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Slide Decks

Not all professional C++ programmers have the opportunity to use Boost at work, nor do all of them choose to spend their free time, as I do, using Boost at home.

Additionally, these slides can be useful even to Boost-experienced programmers. For example:

1. Our shared_ptr allocator support is a C++0x feature, backported to VC9 TR1 (and Boost 1.35, which isn't out yet).

2. Understanding shared_ptr's internal representation is useful to get a feel for how it behaves.

3. It's important to know where Boost differs from TR1. Boost.Regex's grammar contains stuff that TR1 doesn't (for example \< and \>). Also, Boost.Regex supports some function calls that TR1 doesn't (see regex slide 28; I filed a Library Issue about that).

4. Boost's documentation is very good, but even users of Boost.Regex might not be familiar with regex_iterator and regex_token_iterator; my slides provide a useful overview of what they do.

Even the STL is unfamiliar to some professional C++ programmers; the best way to deal with this is education.

Stephan T. Lavavej, Visual C++ Libraries Developer

Saturday, February 23, 2008 4:31 PM by DaveG

# re: TR1 Slide Decks

Great job Stephan.  Thanks for posting this.

Sunday, February 24, 2008 9:49 AM by SvenC

# re: TR1 Slide Decks

Hi Stephan,

it is so silent about MFCNext and TR1. Do you have any information about the release date?

I would like to start using the beta but unfortunately my VS 2008 Team System Developer is not supported. The beta installs only on Professional and Team Suite.

Regards,

Sven

Sunday, February 24, 2008 9:59 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Slide Decks

[SvenC]

> it is so silent about MFCNext and TR1.

That's what this post is for! :-)

> Do you have any information about the release date?

As we mentioned in http://blogs.msdn.com/vcblog/archive/2007/11/09/announcing-a-major-mfc-update-plus-tr1-support.aspx , the Feature Pack will be finalized in Q1 CY 2008, so you can expect to be able to download it soon.

> I would like to start using the beta but

> unfortunately my VS 2008 Team System Developer is

> not supported. The beta installs only on

> Professional and Team Suite.

That's a known bug - one of those things that betas are good for flushing out. While it's unfortunate that the beta wouldn't install on some common SKUs (causing lots of frustration), the good news is that the final version will install on all non-Express SKUs as we originally intended.

Thanks,

Stephan T. Lavavej, Visual C++ Libraries Developer

Sunday, February 24, 2008 11:24 PM by alones

# re: TR1 Slide Decks

Good job!

I'm interested in C++ and TR1. I think that due to such efforts as you are doing your c++ library is getting more powerful debugging features and robustness following C++ standard.

Anyway, to tell an expected defect I guess I write his comment.

Already I wrote a post regarding the defect in MSDN forum (Visual C++ Language)

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2887793&SiteID=1

As you know, many violations of the C++ standard in VC6.0 has been fixed from VC8.0 (or 7.0) and it make developers happy in their life.

I'd like you to look over above article. And if it is not your job or you are busy, could you tell me a person in charge?

Monday, February 25, 2008 9:17 AM by Granville Barnett

# A few slide decks that may be of interest (C++ TR1)

I missed this but last Friday the VC blog guys put up some slide decks on the &quot;new&quot; stuff in

Monday, February 25, 2008 9:46 AM by Stephan T. Lavavej [MSFT]

# re: TR1 Slide Decks

[alones]

> I'd like you to look over above article.

I've posted a reply to that thread. To summarize: Indeed, VC8 and above accepted that code, while VC7.1 and below rejected it, but this is not a library bug. Instead, it's a consequence of VC8's introduction of iterator checking and iterator debugging, which made vector<T>::iterator into a class type (instead of T *). Your code triggers undefined behavior.

Thanks,

Stephan T. Lavavej, Visual C++ Libraries Developer

Monday, February 25, 2008 11:50 AM by alones

# re: TR1 Slide Decks

Yes, right. I have just checked it and found out the reason as you answer through debugging with VC8.0.

As you answer, in case of VC6 vector<T>::iterator is a T*. But in case of VC8 it is a class and the class has operator++ and --.

So, my failure to notice makes this thing.

But I think that to such developer like me the difference of polices between VC6 and VC8 can make a little confusion.

Anyway thanks a lot for your kindly answering with good explanation in MSDN forum.

Gidae Yeo (in Korea)

Monday, February 25, 2008 4:33 PM by Visual C++ Team Blog

# Channel 9: Stephan T. Lavavej: Digging into C++ Technical Report 1 (TR1)

Hello Recently we shipped a beta of our MFC/TR1 Feature Pack that, naturally enough, included a large

Monday, February 25, 2008 5:23 PM by Noticias externas

# Channel 9: Stephan T. Lavavej: Digging into C++ Technical Report 1 (TR1)

Hello Recently we shipped a beta of our MFC/TR1 Feature Pack that, naturally enough, included a large

Monday, February 25, 2008 6:55 PM by Allan Gibbs

# re: TR1 Slide Decks

> Our shared_ptr allocator support is

> a C++0x feature, backported to VC9

> TR1 (and Boost 1.35, which isn't out

> yet).

And neither is C++0x.

I am still disappointed that MS is implementing a non-finalized standard before completing existing decade old standards. Until existing standards fully implemented, your product is simply non-conformant.

One example: in the last few years, I have *inherited* an increasing amount of code utilizing export. I would like to develop with VS, but since you do not support this standard feature, I am forced to use other compilers. Yeah, yeah, I know: "nobody needs export". Regardless, it is being used increasingly and I can not (and am usually not allowed to) rewrite all of the code.

Monday, February 25, 2008 7:18 PM by V12M

# re: TR1 Slide Decks

> Hi, I'm Stephan, the Visual C++ Libraries Developer working on TR1.

You're *the* only developer working on TR1?

Tuesday, February 26, 2008 3:29 AM by to_be_defined

# re: TR1 Slide Decks

I wonder if all those "export" requests are trolls...

Implementing export is very difficult and a waste of time (as the only team that has ever done it admits).

Considering that only EDG-based compilers support it, it is naive to try and use export and then expect to compile on any other compiler.

By the way, I know this is Microsoft, but making the attachments available as PDF would be nice; I don't have Office 2007 or the Office viewers installed.

Tuesday, February 26, 2008 4:03 AM by Stephan T. Lavavej [MSFT]

# re: TR1 Slide Decks

[V12M]

> You're *the* only developer working on TR1?

Within Microsoft, yes.

To clarify:

* We licensed Dinkumware's TR1 implementation, and (as I explained in a previous VCBlog post) they're responsible for implementing the majority of fixes to it. I'm acting as a hybrid developer/reviewer/whitebox tester.

* My manager, Ale Contenti (VC Libraries and IDE dev lead) also reviews Dinkumware's and my checkins, but I'm the "boots on the ground", so to speak.

* The TR1 "feature crew" includes non-developers: tester Rob Huyett, program manager Ayman Shoukry, documentation writer Jim Vance, etc.

So, I'm not locked in a closet somewhere, slaving away over TR1 by myself.

[to_be_defined]

> By the way, I know this is Microsoft, but making

> the attachments available as PDF would be nice; I

> don't have Office 2007 or the Office viewers

> installed.

The PowerPoint Viewer 2007 is freely available (http://www.microsoft.com/downloads/details.aspx?familyid=048dc840-14e1-467d-8dca-19d2a8fd7485&displaylang=en ). (I haven't used it, as I have Office 2007 at work and home, but apparently it works quite well).

As for the lack of PDF - I simply hadn't installed the Save As PDF add-in. If you really want PDF versions, E-mail me (stl@microsoft.com) and I'll get the add-in and create PDFs for you. (I don't know if VCBlog attachments can be updated - there's definitely a one-attachment-per-post limitation, so I'd rather not struggle with that.)

Thanks,

Stephan T. Lavavej, Visual C++ Libraries Developer

Tuesday, February 26, 2008 4:39 AM by Stephan T. Lavavej [MSFT]

# re: TR1 Slide Decks

Oh, and I almost forgot - other VC Libraries devs are working on the Feature Pack packaging, making sure that it installs on all SKUs, uninstalls cleanly, etc.

Stephan T. Lavavej, Visual C++ Libraries Developer

Tuesday, February 26, 2008 8:26 PM by Mainer

# re: TR1 Slide Decks

to_be_defined wrote:

> Implementing export is very difficult and a waste of time (as the only team that has ever done it admits).

Difficult: apparently. However, it should not take a decade or more to implement. If Microsoft developers are not up to the task, then perhaps software development is not the right industry for them.

Waste: perhaps; nevertheless, people are using it. I often think that about roughly 10-15% of the features in the C++ standard are a waste. But I do not argue for them to be removed after the fact.

>Considering that only EDG-based compilers support it, it is naive to try and use export and then expect to compile on any other compiler.

Your logic and argument is naive. The standard exists solely to ensure interoperability between various compilers. Export IS part of the C++ standard and has been for a DECADE now. There were attempts to remove it and the standards committee rejected them.

I am in a similar situation as the earlier poster: a number of my clients are using export which forces me to drop VC++ even though it is my favorite compiler. Thus, with the exception of my own personal projects, I doubt that I will be able to take advantage of the work being done on TR1, at least Microsoft's implementation of it.

Wednesday, February 27, 2008 2:43 AM by to_be_defined

# export

Stephan> Interesting presentations; I was able to install the viewer.

Mainer> Implementing export took 1.5 years of design + 2 man years of coding (according to EDG). Here's the advice EDG gives about implementing export: "Don't.".

The main reason it was kept in the standard is the considerable amount of time EDG spent implementing it; it would have been unfair to remove it.

Wednesday, February 27, 2008 3:24 AM by Mainer

# re: TR1 Slide Decks

to_be_defined,

> 1.5 years of design

A lot of that time was spent seeking clarification on initially unspecified issues with interactions with subsystems. Those issues have since been resolved and need not be repeated.

> 2 man years of coding

That sounds reasonable. There is a new release of VC++ roughly every 2-4 years (1998, 2002, 2003, 2005, 2007).

Even assuming the worst four years and two people, MS should have been able to implement export at least twice in the last decade. Also note that Microsoft has far more resources available to their disposal than EDG, and the design time should not be as long since the above issues have been clarified.

> The main reason it was kept in the standard is the considerable amount of time EDG spent implementing it; it would have been unfair to remove it.

Do you have a resource for that statement? If EDG opposed ("Don't") export, then fairness is hardly very important.

Here are the actual minutes:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1459.html

There was more than three times the support for keeping export than removing it.

"Remove export: 8"

"Leave in export: 28"

Personally, I neither like nor dislike export; I'd say that I am neutral. However, I have customer code that uses it and need to compile it as is. That pretty much eliminates VC++ as an option.

Friday, February 29, 2008 12:03 PM by ikk

# re: TR1 Slide Decks

Wow, look at what i have found (the link points to a google groups search):

http://groups.google.com/groups/search?q=c%2B%2B+can%27t+afford+export+debunked&qt_s=Search

"Can't afford export" was debunked! :-O

Too bad i hadn't found this earlier. I that thread, Daveed Vandevoorde states that the claim that export is underspecified is "a serious exageration."

Until today, I thought that the article "Why we can't afford export" was a good reference about the problems with export. Now i am not sure anymore...

Besides Comeau, is there any other compiler with export? (other EDG-based compilers, i mean... becaus non-EDG compilers certainly don't support export)

Friday, February 29, 2008 1:46 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Slide Decks

[ikk]

> Daveed Vandevoorde states that the claim that

> export is underspecified is "a serious exageration."

Vandevoorde is an expert - but the experts disagree. I don't consider Sutter's paper to have been "refuted".

Most important are two words: opportunity cost.

Stephan T. Lavavej, Visual C++ Libraries Developer

Saturday, March 01, 2008 11:47 AM by Cannot believe it..

# re: TR1 Slide Decks

This 'export' freak really needs to go and get some life out there, or buy EDG and be over it.

Frankly, whoever is your manager, and all those .NET PM managers are to blame as much, they should be taken out and beaten by an oakwood stick.

Putting one man to do TR1 just shows how far behind Linux and Google infrastructure MS will be once it gains adoption one of these years.

Someone over there needs a good GC and LINQ invention slapping and some proper Bjarne lectures in metaprogramming and better than half-decent support for value-type generics.

Oh, I forget, they are all mass market architects.. Delphi delegates bloatware style.

Sunday, March 02, 2008 6:55 PM by Michael P.

# re: TR1 Slide Decks

A colleague pointed me to this thread. I was a long-time user of Visual C++. It's a very productive environment. Unfortunately, I am unable to use it anymore. Like some of the people above me, several of my long-term clients use export and I have had to abandon VC++ for more compliant compilers. I respect that Microsoft may have other priorities beside the standard; however, it sure would be nice to do my daily work again someday with VC++.

Monday, March 03, 2008 7:23 AM by ikk

# re: TR1 Slide Decks

"""I have had to abandon VC++ for more compliant compilers."""

Which ones? Last time i checked it out, only Comeau supported it. Maybe the Intel compiler also supports export since it is EDG-based. Is there anything i am missing?

Monday, March 03, 2008 10:00 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Slide Decks

[Cannot believe it..]

> Putting one man to do TR1

Does "20% of the VC Libraries developers" sound more impressive?

> just shows how far behind Linux and Google

> infrastructure MS will be once it gains

> adoption one of these years.

Linux is a compiler? Google ships a compiler?

GCC, on the other hand, is a compiler. 4.2 has partial TR1 support, but you need the not-yet-released 4.3 for <regex>.

[ikk]

> Is there anything i am missing?

GCC doesn't support export (and although I don't follow their development closely like when I was in college, they don't appear to be moving towards it at all).

Code using export may be theoretically-portable, but it is not actually-portable to the Big Dog compilers, VC and GCC.  (Market share numbers would be fascinating - but my understanding is that VC is the most widely used Windows-targeting compiler, just as GCC is the most widely used Unix-targeting compiler.)

Stephan T. Lavavej, Visual C++ Libraries Developer

Thursday, March 06, 2008 2:16 AM by LM

# re: TR1 Slide Decks

STL, I'm glad to see you've landed on the VC++ team.  Keep up the good fight.

On export, I can't imagine they're anything but trolls.  Comeau and recent versions of C++ Builder support it, sure, but lets face it -- the interaction of ADL and export presents profound difficulties and (probably) demands that exported templates contain almost as much information as the source.

Sunday, March 09, 2008 8:23 PM by Troll

# re: TR1 Slide Decks

Just change your name to Eric Xavier Paul Othello Robert Trudeau and ship the new compiler from your new e-mail address.

Thursday, March 13, 2008 12:19 AM by PJK

# re: TR1 Slide Decks

LM wrote:

> the interaction of ADL and export presents profound difficulties and (probably) demands that exported templates contain almost as much information as the source.

Fear mongering aside, all of the above is entirely immaterial. As per the decade old standard, the compiler just needs to compile standard code. VC++ does not do that with respect to export.

Thursday, March 13, 2008 5:51 PM by user

# re: TR1 Slide Decks

Plz someone supply slides in pdf format or .ppt format. I don't have windows sry for bugging you in an msdn blog, but as m$ claims for interoperability I will ask for those pdfs too, they sound interesting :)

Thursday, March 13, 2008 9:31 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Slide Decks

You can search for online PPTX to PDF converters (I easily found one, although I haven't used it), or you can E-mail me at stl@microsoft.com - although I don't know if I can mail a 26.4 MB .tar.bz2 file.

Stephan T. Lavavej, Visual C++ Libraries Developer

Monday, March 24, 2008 12:34 PM by vcblog

# re: TR1 Slide Decks

Stephan T. Lavavej on Channel 9 - on C++ Technical Report 1 (TR1)

Hello

In case you missed it, Charles Torre (Channel 9) recently visited with Stephan and discussed what we are providing and what VC++ developers can gain by using TR1 in our VS2008 Feature Pack. We hope you enjoy the video! http://channel9.msdn.com/Showpost.aspx?postid=385821

Thanks

Damien

Monday, April 07, 2008 8:53 AM by Visual C++ Team Blog

# Visual C++ 2008 Feature Pack Released!

The final release of the Visual C++ 2008 Feature Pack is now available for download. This release provides

Monday, April 07, 2008 11:58 AM by bkchung's WebLog

# Visual C++ 2008 Feature Pack RTWed!

Visual C++ Team Blog : Visual C++ 2008 Feature Pack Released! Download details Visual C++ 2008 Feature

Monday, April 07, 2008 1:41 PM by Johan Lindfors

# Visual C++ 2008 Feature Pack

Nu finns ett s&#229; kallat Feature Pack till Visual C++ 2008 att ladda he m f&#246;r alla kunder med

Friday, April 11, 2008 10:09 AM by Is This Thing On?

# C++ Gets Some Love

Good news from the C++ Team!! &#160; ================== The final release of the Visual C++ 2008 Feature

Tuesday, April 29, 2008 4:05 AM by Andrew Coates ::: MSFT

# Visual C++ 2008 Feature Pack Released

During my Windows Development session at the Heroes Happen { 2008 } launch shows around the country,

Monday, June 30, 2008 1:29 PM by Visual C++ Team Blog

# TechEd 2008 - meeting customers at the booth!

Hello, my name is Li Shao. I am a Software Design Engineer in Test in Visual C++ team. From June 3 to

New Comments to this post are disabled
 
Page view tracker