译者:yurunsun@gmail.com 新浪微博@孙雨润 新浪博客 CSDN博客日期:2012年11月12日
原作:Scott Meyers
这些是Scott Meyers培训教程《新C++标准:C++0x教程》的官方笔记,培训课程的描述请见 http://www.aristeia.com/C++0x.html,版权信息请见 http://aristeia.com/Licensing/licensing.html.
漏洞和建议请发送邮件到 smeyers@aristeia.com. 翻译错误请发送邮件给yurunsun@gmail.com (译者注).
1. 教程内容一览
- 导论:历史和名词、C++98/C++0x的快速比较。
- 面向所有开发者的特性:
auto
关键词、基于范围的for
关键词、lambdas, 线程等等 - 库的改善:更多特性、基于tr1的功能、
forward_list
,unique_ptr
等等 - 类的开发者特性:
move
语义、完美forwarding、委托/继承构造函数等等 - 面向库的开发者特性:可变参数宏、
decltype
等等 - 面向其他特性
- 移除和废弃的特性
2. 导论
2.1 历史和名词
- 1998: ISO C++标准正式启用 C++98
- 2003: TC1(Technical Corrigendum 1)发布 C++03
- 2005: TR1(Technical Report 1") 发布
- 2008: 新C++标准草案
- 2009: 一些C++0x特性开始逐渐通用
- 2011: 新标准正式批准
- 2012: TR2添加了新的标准库组件
编译器对C++0x支持进度表请见 http://www.aristeia.com/C++0x/C++0xFeatureAvailability.htm
2.2 gcc打开c++0x特性(译者增补部分)
- 最好使用gcc4.6版本以上
- Makefile增加编译选项
-std=gnu++0x
- 如果使用qmake则在*.pro文件中增加编译选项
QMAKE_CXXFLAGS += -std=gnu++0x
2.3 Copying和Moving
C++一直支持对象状态的拷贝,例如拷贝构造函数、赋值符号。 C++0x增加了对移动对象状态的支持:
Widget w1;
Widget w2(w1);
Widget w3;
Widget w4(std::move(w3));
临时对象是使用moving的首选:
typedef std::vector<T> TVec;
TVec createTVec(); // 工厂函数
TVec vt;
vt = createTVec(); // C++98中,将返回值copy给vt,然后销毁返回值
vt = createTVec(); // C++0x中隐式使用move请求
尽管后面会详细讨论move语义,但这里预热几点:
- Moving是新C++的关键思想:是对copy的优化操作
- 新C++绝大多数标准类型都能被move:例如STL的容器
- 有些类型不能被copy,但可以被move:例如stream, std::stream, std::unique_ptr等等
2.4 在一段样例程序中对比C++98与C++0x
我们写程序来列出下面书籍中前20个最常用的单词:
Alice_in_Wonderland.txt War_and_Peace.txt
Dracula.txt The_Kama_Sutra.txt The_Iliad.txt
70544 words found.
Most common:
the 58272
and 34111
of 27066
to 26992
a 16937
in 14711
his 12615
he 11261
that 11059
was 9861
with 9780
I 8663
had 6737
as 6714
not 6608
her 6446
is 6277
at 6202
on 5981
for 5801
2.4.1 C++98程序的写法
#include <cstdio> // easier than iostream for formatted output
#include <iostream>
#include <iterator>
#include <string>
#include <fstream>
#include <algorithm>
#include <vector>
#include <map>
typedef std::map<std::string, std::size_t> WordCountMapType;
WordCountMapType wordsInFile(const char * const fileName) { // for each word in file, return
std::ifstream file(fileName); // # of occurrences
WordCountMapType wordCounts;
for (std::string word; file >> word; ) {
++wordCounts[word];
}
return wordCounts;
}
struct Ptr2Pair2ndGT { // compare 2nd components of pointed-to pairs
template<typename It>
bool operator()(It it1, It it2) const {
return it1->second > it2->second;
}
};
template<typename MapIt> // print n most
void showCommonWords(MapIt begin, MapIt end, const std::size_t n) { // common words in [begin, end)
typedef std::vector<MapIt> TempContainerType;
typedef typename TempContainerType::iterator IterType;
TempContainerType wordIters;
wordIters.reserve(std::distance(begin, end));
for (MapIt i = begin; i != end; ++i) {
wordIters.push_back(i);
}
IterType sortedRangeEnd = wordIters.begin() + n;
std::partial_sort(wordIters.begin(), sortedRangeEnd, wordIters.end(), Ptr2Pair2ndGT());
for (IterType it = wordIters.begin(); it != sortedRangeEnd; ++it) {
std::printf(" %-10s%10u\n", (*it)->first.c_str(), (*it)->second);
}
}
int main(int argc, const char** argv) {
// take list of file names on command line, print 20 most common words within
WordCountMapType wordCounts;
for (int argNum = 1; argNum < argc; ++argNum) {
// copy map returned by wordsInFile (modulo compiler optimization)
const WordCountMapType results = wordsInFile(argv[argNum]);
for (WordCountMapType::const_iterator i = results.begin(); i != results.end(); ++i) {
wordCounts[i->first] += i->second;
}
}
std::cout << wordCounts.size() << " words found. Most common:\n" ;
const std::size_t maxWordsToShow = 20;
showCommonWords( wordCounts.begin(), wordCounts.end(),
std::min(wordCounts.size(), maxWordsToShow));
}
2.4.1 C++0x程序的写法
#include <cstdio>
#include <iostream>
#include <iterator>
#include <string>
#include <fstream>
#include <algorithm>
#include <vector>
#include <unordered_map>
#include <future>
using WordCountMapType = std::unordered_map<std::string, std::size_t>;
WordCountMapType wordsInFile(const char * const fileName) { // for each word in file, return # of occurrences
std::ifstream file(fileName);
WordCountMapType wordCounts;
for (std::string word; file >> word; ) {
++wordCounts[word];
}
return wordCounts;
}
// print n mostcommon words in [begin, end)
template<typename MapIt> //
void showCommonWords(MapIt begin, MapIt end, const std::size_t n) {
// typedef std::vector<MapIt> TempContainerType;
// typedef typename TempContainerType::iterator IterType;
std::vector<MapIt> wordIters;
wordIters.reserve(std::distance(begin, end));
for (auto i = begin; i != end; ++i) {
wordIters.push_back(i);
}
auto sortedRangeEnd = wordIters.begin() + n;
std::partial_sort(wordIters.begin(), sortedRangeEnd, wordIters.end(),
[](MapIt it1, MapIt it2){return it1->second > it2->second; });
for (auto it = wordIters.cbegin(); it != sortedRangeEnd; ++it) {
std::printf(" %-10s%10zu\n", (*it)->first.c_str(), (*it)->second);
}
}
int main(int argc, const char** argv) {
// take list of file names on command line, print 20 most common words within process files concurrently
std::vector<std::future<WordCountMapType>> futures;
for (int argNum = 1; argNum < argc; ++argNum) {
futures.push_back(std::async([=]{ return wordsInFile(argv[argNum]); }));
}
WordCountMapType wordCounts;
for (auto& f : futures) {
const auto results = f.get(); // move map returned by wordsInFile
for (const auto& wordCount : results) {
wordCounts[wordCount.first] += wordCount.second;
}
}
std::cout << wordCounts.size() << " words found. Most common:\n" ;
const std::size_t maxWordsToShow = 20;
showCommonWords( wordCounts.begin(), wordCounts.end(),
std::min(wordCounts.size(), maxWordsToShow));
}