文章出自:
http://hi.baidu.com/%B6%E0%CE%AC%CA%FD%D7%E9/blog/item/1ad04e54e38e3455574e0017.html
c++0x中,ox指新标准发布的时间。C++标准五年发布一次。
================================================================
最近,从全球最活跃的C++社区boost传来消息,新的C++标准:C++0x,最早将在2007年10月发布。很早就有人猜测,C++0x中的x到底是8还是9,不过现在看来很可能是7,但是也不尽然,因为上一个C++标准本来计划是1997年发布,但是因为STL的引入而推迟到1998年。这次又遇到了相同的情况,大家都不怀疑TR1和TR2(Technical Report)将成为新标准的一部分,但是随着越来越多的boost库被移到TR2中,TR2的进一个完善很可能拖新标准的后腿。不过,C++0x是C++的一次重大升级,恐怕编译器厂商最快也只能在2009年推出符合新标准的编译器。
新的C++标准将在几个方面对C++标准进行扩充:
从上一个标准C++98发布到现在,将近有10年的时间了,在这十年的时间里编程语言发生了翻天覆地的变化,首先是JAVA异军突起,然后是微软借助.NET平台的优势推出了C#,C++已经不再是编程语言中的明星了,它被挤下了神坛,慢慢沦为边缘编程语言。这中间的主要原因并不是C++的语法落伍了,而是使用C++开发软件效率低下并且容易出错。效率低下的原因是因为C++缺少库的支持,C++只提供了编程语言的基本功能,缺少强有力的库支持,比如字符串处理就一直是C++的诟病。容易出错的原因是C++从C继承了动态内存分配和指针,这一点被认为是软件发生错误的根源,虽然C++引入STL来解决这个问题,比如用vector代替内置数组可以防止内存泄漏,用迭代器代替直接下标操作可以防止地址越界。但是STL毕竟太简单了,比如字符串处理就只有一个简单的string,比起Perl差远了。C++唯一的优势就是速度,但是随着处理器和内存的快速发展也慢慢被遗忘了,所以就沦落到了现在的地步。
C++要想摆脱这种局面,就必须解决这两个问题,而在新标准中我们已经看到了答案。TR1和TR2已经成为新的标准库的一部分,它们不仅提供了象“正则表达式”和“哈希表”这样程序员盼望已久的功能,还有针对多核处理器的并发内存模型和并发库,对网络也有socket库等等。针对内存出错问题,新标准通过强化STL代替内存访问,使用垃圾收集器防止内存泄漏。在C++社区上关于新标准讨论最多的就是到底应不应该修改C++语言,争论的核心之一就是垃圾收集器。老鸟们总是认为“不要为了新手而将C++降格,适合新手的语言已经有很多了!”,很多C++程序员认为新标准应该将精力集中于扩充标准库,而不是解决内存泄漏问题,因为那是程序员自己的事。在本人看来这种思想将会害死C++,因为现实中总是新手比老鸟多,软件公司的老板招一个程序员是希望他(她,它)能够立即开始编写没有错误的代码,而不是培养他们知道他们成为专家后再开始干活,所以,如果C++不能成为一种“菜鸟友好”的语言,那么C++的堕落将不可避免。设想某个程序员分配了一块内存而忘记释放它,但是垃圾收集器捕获了这个异常并默默地替他释放了这块内存,从而使内存泄漏这种悲惨的事情得以避免,而程序运行起来状态良好,那还有什么理由不在C++中添加垃圾收集功能呢?
C++0x能够重振C++的雄风吗?有了垃圾收集器的C++,并且所有内存和指针操作都被“友好地”建议用STL代替,那还是C++吗?还是另一个JAVA?答案当然是“这仍旧是C++,请放心使用”,不过C++0x之后还会有什么新的内容,会不会有一套GUI库?如果是那样的话就真的成JAVA了。
====================================================================
The C++ Source
A Brief Look at C++0x
by Bjarne Stroustrup
January 2, 2006
Bjarne offers a sneak peek at the next version of standard C++ ("C++0x") which should be complete by 2009.
The work on C++0x has entered a decisive phase. The ISO C++ committee aims for C++0x to become C++09. It follows that the standard must be complete for ratification by the ISO member nations in 2008. The set of facilities offered will be chosen from those currently being considered. To finish in time, the committee has stopped looking for new proposals and concentrates on the ones already being considered.
This paper briefly outlines the guiding principles of the work on C++0x, presents a few examples of likely language extensions, and lists some proposed new standard libraries.
[Note: This paper was first presented to the "Modern C++ Design & Programming" conference in Shanghai, November 18, 2005]
C++ is a general-purpose programming language with a bias towards systems programming that:
By "systems programming", I mean programming the kind of tasks traditionally associated with the operating system and fundamental tools. This includes the operating system kernel, device drivers, system utilities, networking, word processing tools, compilers, some kinds of graphics and GUI, database systems, games engines, CAD/CAM, telecommunications systems, etc. This kind of work is strongly represented among current C++ users. For example, see my "applications" page: http://www.research.att.com/~bs/applications.html.
The aim of C++0x is for that characterization above to remain true. It is not an aim to eliminate one of those styles (or "paradigms"; e.g. to make C++ less compatible with C) or to add a radically new paradigm. The most effective styles of programming use a combination of these techniques. Using these techniques in concert is often called "multi-paradigm programming," so we can say that we want to improve C++ as a multi-paradigm programming language.
The high level aims for the language part of C++0x are to:
Make C++ a better language for systems programming and library building
Rather than providing specialized facilities for a particular sub-community (e.g., numeric computation or Windows-style application development)
Make C++ easier to teach and learn
Through increased uniformity, stronger guarantees, and facilities supportive of novices
In other words, C++0x should be better than C++98 where C++98 is already strong—and maybe in a few more areas that are natural generalizations of what C++98 supports. When it comes to supporting specialized application areas, such as numeric computation, Windows-style application development, and embedded systems programming, C++0x will rely on libraries. The efficiency of the basic language features (such as, stack-allocated objects and pointers) plus the generality and flexibility of its abstraction mechanisms (such as classes and templates) make the use of libraries attractive in an incredibly broad set of application areas and reduce the need for new language features.
We cannot make the language simpler to teach and learn by removing features. Stability and compatibility are major concerns, so eliminating anything of importance (in any way) is not an option (and eliminating something of no importance would not be a help). This leaves us with the options of generalizing rules and adding easier-to-use features. We aim at both, but the latter is easier. For example, better library facilities, such as containers and algorithms, save users from some of the problems associated with lower-level facilities like arrays and pointers. Language facilities that simplify the definition and use of libraries (such as concepts and generalized initializer lists—see below) will therefore contribute to the ease of use of C++0x.
Some people object: "Don't dumb-down C++ for novices—there are languages enough for those", or "The sooner novices become experts the better!" These people have a point, but there will always be more novices than experts. Many C++ users quite reasonably don't want to become C++ experts—they are experts in their own fields (e.g., physicists, graphics specialists, or hardware engineers) who use C++. In my opinion, C++ has become too "expert friendly" and it will cost us little to provide much better support for "novices". It will cost us nothing in terms of performance (the zero-overhead principle still holds), in flexibility (we don't propose to prohibit anything), or in terseness of code. On the contrary, we aim to simplify expression of ideas. Finally, C++ is so large, is used in so many application areas, and there are so many useful C++ design techniques, that we are all "novices" much of the time.
The C++0x improvements should be done in such a way that the resulting language is easier to learn and use. Among the rules of thumb for the committee are:
Provide stability and compatibility (with C++98, and, if possible, with C)
Prefer standard library facilities to language extensions
Make only changes that change the way people think
Prefer generality to specialization
Support both experts and novices
Increase type safety (by providing safe alternatives to currently unsafe facilities)
Improve performance and ability to work directly with hardware
Fit into the real world
Naturally, applying these ideals and rules is an art rather than a science and people can (and do) disagree on what is a natural development of C++ and what would be a new paradigm. C++0x will most likely support optional garbage collection and it will support concurrency in the form of a machine model plus standard library facilities supporting threads (and maybe more). Some would consider that radical, but I don’t; people have used garbage collection with C++ for years (where that makes sense) and just about everybody uses threads sometime. In these cases, the issue is simply to standardize current practice.
We try to focus on extensions that "change the way people think" because that way we gain the greatest benefits for our efforts. Every change has a cost in terms of implementation, learning, etc., and the cost of a change does not always directly relate to its benefits. The major advances/benefits do not come from improving the way a programmer writes an individual line of code, but from improving the way a programmer solves problems and organizes programs. Object-oriented programming and generic programming have changed the way many people think—and that was the purpose of the C++ language facilities supporting those styles. Thus, the best use of our time as language and library designers is to work on facilities and techniques that help change the way people think.
Please note the last rule, "Fit into the real world". As usual for C++, the aim is not to create the most beautiful language—though we all prefer elegance when we can get it—but to provide the most useful language. This implies that compatibility, performance, ease of learning, and interoperability with other systems and languages are serious interrelated concerns.
Let’s see how code using new C++0x features might look:
template<class T> using Vec = vector<T,My_alloc<T>>;
Vec<double> v = { 2.3, 1.2, 6.7, 4.5 };
sort(v);
for(auto p = v.begin(); p!=v.end(); ++p)
cout << *p << endl;
Each line except the last is illegal in C++98, and in C++98 we’d have to write more (error-prone) code to get the work done. I hope you can guess the meaning of this code without explanation, but let’s look each line individually.
template<class T> using Vec = vector<T,My_alloc<T>>;
Here, we define Vec<T>
to be an alias of vector<T,My_alloc<T>>
. That is, we define a vector called Vec
that works exactly like vector
except that it uses my allocator (My_alloc
) rather than the default allocator. The ability to define such aliases and to bind some but not all parameters of a template has been missing from C++. It has traditionally been referred to as a "template typedefs" because typedef is what we typically use for defining type aliases, but for technical reasons, we preferred using. One advantage of this syntax is that it introduces the name being defined where it is easy for the human reader to spot. Note also another detail. I didn’t write
template<class T> using Vec = vector< T,My_alloc<T> >;
It will no longer be necessary to add that space between the terminating >'s. These two extensions have already been accepted in principle.
Next we define and initialize a Vec
:
Vec<double> v = { 2.3, 1.2, 6.7, 4.5 };
Initializing a user-defined container (vector<double,My_allocator<double>>
) with an initializer list is new. In C++98, we can only use such initializer lists for aggregates (arrays and classic struct
s). Exactly how this extension will be achieved is still being discussed, but the solution will most likely involve a new kind of constructor—a "sequence constructor". Allowing the above implies that C++ better meets one of its fundamental design criteria: support user-defined and built-in types equally well. In C++98 arrays have a notational advantage over vector
s. In C++0x, that will no longer be the case.
Next, we sort the vector:
sort(v);
To do that within the framework of the STL we must overload sort
for containers and for iterators. For example:
template<Container C> // sort container using <
void sort(C& c);
template<Container C, Predicate Cmp> // sort container using Cmp
where Can_call_with<Cmp,typename C::value_type>
void sort(C& c, Cmp less);
template<Random_access_iterator Ran> // sort sequence using <
void sort(Ran first, Ran last);
template<Random_access_iterator Ran, Predicate Cmp> // sort sequence using Cmp
where Can_call_with<Cmp,typename Ran::value_type>
void sort(Ran first, Ran last, Cmp less);
This illustrates the most significant proposed C++0x language extension that is likely to be accepted: concepts. Basically, a concept is the type of a type; it specifies the properties required of a type. In this case, the concept Container
is used to specify that the two first versions of sort
need an argument that meets the standard library container requirements. The where
-clauses are used to specify the required relationship between the template arguments: that the predicates can be applied to the containers' element types. Given concepts we can provide far better error messages than is currently possible and distinguish between templates taking the same number of arguments, such as
sort(v, Case_insensitive_less()); // container and predicate
and
sort(v.begin(), v.end()); // two random access iterators
The difficulty in the design of “concept” is to maintain the flexibility of templates so that we don’t require template arguments to fit into class hierarchies or require all operations to be accessed through virtual functions (as for Java and C# generics). In “generics”, an argument must be of a class derived from an interface (the C++ equivalent to “interface” is “abstract class”) specified in the definition of the generic. That means that all generic argument types must fit into a hierarchy. That imposes unnecessary constraints on designs requires unreasonable foresight on the part of developers. For example, if you write a generic and I define a class, people can't use my class as an argument to your generic unless I knew about the interface you specified and had derived my class from it. That's rigid.
There are workarounds, of course, but they complicate code. Another problem is that you cannot use built-in types directly with generics, because built-in types, such as int
, are not classes and don't have the functions required by interfaces specified by a generic—you then have to make wrapper classes for holding built-in types and access elements indirectly through pointers. Also, the typical operation on a generic is implemented as a virtual function call. That can be very expensive (compared to just using a simple built-in operation, such as + or <). Implemented that way, generics are simply syntactic sugar for abstract classes.
Given "concepts", templates will retain their flexibility and performance. There is still much work left before the committee can accept a specific and detailed concept design. However, concepts are a most likely extension because they promise significantly better type checking, much better error messages, and greater expressive power. That should lead to significantly better library interfaces, starting with the current standard containers, iterators, and algorithms.
Finally, consider the last line that outputs the elements of our vector:
for (auto p = v.begin(); p!=v.end(); ++p)
cout << *p << endl;
The difference from C++98 here is that we don’t have to mention the type of the iterator: auto
means “deduce the type of the declared variable from the initializer”. Such uses of auto
are far less verbose and also less error-prone than current alternatives, such as:
for (vector< double, My_alloc<double> >::const_iterator p = v.begin(); p!=v.end(); ++p)
cout << *p << endl;
The new language features mentioned here are all aimed at simplifying generic programming. The reason is that generic programming has become so popular that it is seriously strains the language facilities. Many “modern” generic programming techniques border on “write only” techniques and threaten to isolate its users. To make generic programming mainstream, as object-oriented programming was made mainstream, we must make template code easier to read, write, and use. Many current uses are too clever for their own good. Good code is simple (relative to what it is trying to do), easy to check, and easy to optimize (i.e., efficient). This implies that a wide range of simple ideas can be expressed simply in C++0x and that the resulting code is uncompromisingly efficient. The former is not the case in C++98—at least not for a sufficiently large range of techniques relying on templates. Better type checking and more extensive use of type information to shorten code will make code shorter and clearer, and easier to maintain, as well as more likely to be correct.
Ideally, we’d leave the C++ language mostly unchanged and focus on adding standard libraries. However, libraries that are sufficiently general to be standard are not easy to design and the standards committee is—as usual—short of resources. We are a relatively small group of volunteers and all have “day jobs”. This puts unfortunate limits on how adventurous we can be with new libraries. On the other hand, the committee started early and a technical report on libraries ("The Library TR") was recently approved by vote. It provides several facilities that are directly useful to programmers:
I particularly appreciate having standard versions of regular expression matching and hash tables (called unordered_map
s) available. In addition, the Library TR provides extensive facilities for builders of generic libraries building on the STL:
This is not the place to go into details about these libraries or into the further facilities that the committee would like to provide. If you are interested, I suggest you look at the proposals on the WG21 site (see “information sources” below), the libraries “wish list” (on my home pages), and the BOOST libraries (www.boost.org). I personally would like to see more libraries that are immediately useful to applications builders, such as Beman Dawes’ library for manipulating files and directories (currently a BOOST library) and a socket library.
The list of proposals is still quite modest and not anywhere as ambitious as I’d like. However, more proposals from the committee's large backlog of suggestions are being considered and more libraries will appear either as part of the C++0x standard itself or as further committee technical reports. Unfortunately, lack of resources (time, money, skills, people, etc.) will continue to limit progress in this direction. Sadly, I cannot offer hope for the most frequently wished for new standard library: a standard GUI library. A GUI library is simply too large a task for the volunteers of the C++ standards committee to handle and too difficult a task given the many (non-standard but huge, useful, and supported) GUI libraries available. Please notice that even though they are not standard, the major C++ GUIs have more users than most programming languages and are often better supported.
In addition to these general-purpose libraries, the committee presented a library interface to the most basic level of hardware in its “Performance TR”. That TR is primarily aimed to help embedded systems programmers and to disprove myths about poor performance of C++ code and about C++ being unsuitable for low-level tasks.
“Drawing all shapes in an array” is a classical example of object-oriented programming (going back to the early Simula days). Using generic programming, we can generalize that to drawing each element of any container holding (pointers to) shapes:
template<Container C>
void draw_all(C& c)
where Usable_as<typename C::value_type,Shape*>
{
for_each(c, mem_fun(&Shape::draw));
}
In C++0x, we hope to have Container
as a standard concept and Usable_as
as a standard predicate. The for_each
algorithm is already in C++98, but the version that takes a container (rather than a pair of iterators) will have to wait for concepts in C++0x. The where
-clause is a mechanism through which an algorithm can express requirements on its arguments. Here, draw_all()
requires (obviously) that the elements of the container must be usable as (implicitly convertible to) Shape*
. In this case, the where-clause gives us a degree of flexibility/generality not offered by simply requiring a container of Shape*
's. In addition to any container of Shape*
's, we can use any container with elements that can be used as Shape*
's, such as a list<shared_ptr<Shape*>>
(where shared_ptr
is a likely C++0x standard library class) or a container of pointers to a class derived from Shape*
, such as deque<Circle*>
.
Assuming that we have points p1
, p2
, and p3
, we can test draw_all()
like this
vector<Shape*> v = {
new Circle(p1,20),
new Triangle(p1,p2,p3),
new Rectangle(p3,30,20)
};
draw_all(v);
list<shared_ptr<Shape*>> v2 = {
new Circle(p1,20),
new Triangle(p1,p2,p3),
new Rectangle(p3,30,20)
};
draw_all(v2);
The "draw all shapes" example is important because when you can do that well, you can do much of what’s key to object-oriented programming. As written here, the example demonstrates the power of multi-paradigm programming by also employing generic programming (concepts and templates), conventional programming (e.g. the free-standing standard-library function mem_fun()
), and simple data abstraction (the function object returned by mem_fun()
). Thus, this simple example opens the door to a host of elegant and efficient programming techniques.
I hope that after looking a bit at this example, your reaction will be "How simple!" rather than "How clever! How advanced!" In my opinion, many people are trying too hard to be clever and advanced. The real aim of design and programming is to produce the simplest solution that does the job and express it in the clearest possible way. The aim of the C++0x design is to better support such simple solutions.
My web pages (http://www.research.att.com/~bs) contain much useful information. There you will find information about my own work (books, articles, interviews, FAQs, etc.) and links to sources that I find most helpful, such as a list of interesting C++ applications, a list of C++ compilers, and links to useful libraries (e.g., BOOST). In connection with C++0x, you can find:
Thanks to Rong Yao ("Royal") who encouraged me to clarify many points. Also thanks to Nicholas Stroustrup, Bjorn Karlsson, and students from my 689 class for their helpful comments.
Bjarne Stroustrup is the designer and original implementor of the C++ Programming Language. He is currently the College of Engineering Endowed Chair in Computer Science at Texas A&M University. He formerly worked as the head of AT&T Lab's Large-scale Programming Research department, from its creation until late 2002.
翻译:
template<class T> using Vec = vector<T,My_alloc<T>>;
Vec<double> v = { 2.3, 1.2, 6.7, 4.5 };
sort(v);
for(auto p = v.begin(); p!=v.end(); ++p)
cout << *p << endl;
template<Container C> // sort container using <
void sort(C& c);
template<Container C, Predicate Cmp> // sort container using Cmp
where Can_call_with<Cmp,typename C::value_type>
void sort(C& c, Cmp less);
template<Random_access_iterator Ran> // sort sequence using <
void sort(Ran first, Ran last);
template<Random_access_iterator Ran, Predicate Cmp> // sort sequence using Cmp
where Can_call_with<Cmp,typename Ran::value_type>
void sort(Ran first, Ran last, Cmp less);