在C ++ 11中弃用了哪些C ++习惯用法
新标准有了新的办法,有许多比老办法好,但老办法还是不错的。 出于向下兼容性的原因,新标准也没有被正式弃用。 所以现在的问题是:
旧的编码方式肯定比C ++ 11风格差,我们现在可以做些什么呢?
在回答这个问题时,你可以跳过“使用自动variables”这类显而易见的东西。
- Final Class :C ++ 11提供了
final
说明符来防止类派生 - C ++ 11 lambda大大减less了对命名函数对象(函子)类的需求。
- 移动构造函数 :由于rvalue引用的一stream支持,std :: auto_ptr工作的神奇方式不再需要。
- 安全布尔 :这是前面提到的。 C ++ 11的显式运算符消除了这个非常常见的C ++ 03习惯用法。
- 缩小拟合 :许多C ++ 11 STL包含提供
shrink_to_fit()
成员函数,这应该消除与临时的需要交换。 - 临时基类 :一些旧的C ++库使用这个相当复杂的习惯用法。 移动语义不再需要。
- types安全枚举枚举在C ++ 11中是非常安全的。
- 禁止堆分配 :“= delete”语法是一种更为直接的方式,即明确拒绝特定的function。 这适用于防止堆分配(即,=删除会员操作员新),防止副本,分配等。
- 模板化typedef :C ++ 11中的别名模板减less了对简单模板types定义的需求。 但是,复杂types的生成器仍然需要元函数。
- 一些数值编译时计算,如斐波那契可以很容易地用广义常量expression式replace
- result_of :类模板result_of的使用应该被decltypereplace。 我认为result_of在可用时使用decltype。
- 类内成员初始值设定项可保存非缺省值的非静态成员的初始化初始值。
- 在新的C ++ 11代码中,应该将NULL重新定义为nullptr,但是请参阅STL的讨论 ,了解为什么他们决定反对它。
- expression式模板狂热分子很高兴在C ++ 11中有尾随的返回types函数语法。 没有更多的30行长返回types!
我想我会在那里停下来!
在某个时间点上,有人认为应该按照常值而不是按价值返回:
const A foo(); ^^^^^
这在C ++ 98/03中几乎是无害的,甚至可能会遇到如下几个错误:
foo() = a;
但是通过const
返回在C ++ 11中是禁忌的,因为它禁止移动语义:
A a = foo(); // foo will copy into a instead of move into it
所以只要放松一下,编码:
A foo(); // return by non-const value
只要你可以放弃0
和NULL
来支持nullptr
,那就这样做!
在非generics代码中,使用0
或NULL
不是什么大不了的事情。 但是一旦开始在generics代码中传递空指针常量,情况就会迅速改变。 当你传递0
给template<class T> func(T)
T
被推断为一个int
而不是一个空指针常量。 之后它不能被转换回空指针常量。 如果宇宙只使用nullptr
,这就陷入了根本不存在的问题的泥潭。
C ++ 11不会将0
和NULL
作为空指针常量使用。 但是你应该像编码一样编码。
安全布尔成语 → explicit operator bool()
。
私有拷贝构造函数(boost :: noncopyable)→ X(const X&) = delete
使用私有析构函数和虚拟inheritance来模拟final类 → class X final
在C ++ 11中避免编写基本algorithm的一件事是将lambdaexpression式与标准库提供的algorithm结合使用。
我现在正在使用这些方法,通过使用count_if(),for_each()或其他algorithm而不必再次编写该死的循环,多么频繁地告诉你想要做什么。
一旦你使用了一个完整的C ++ 11标准库的C ++ 11编译器, 你就没有理由不使用标准的algorithm来构build你的 。 Lambda只是杀了它。
为什么?
在实践中(在我自己用这种方法编写algorithm之后),读一些用简单的词语来构build的东西比用一些你不得不解密的循环来理解它的意义要容易得多。 也就是说,自动推导lambda参数将有助于使语法更容易与原始循环相比较。
基本上,使用标准algorithm制作的阅读algorithm比单词隐藏循环的实现细节要容易得多。
我猜测现在只有更高层次的algorithm需要考虑,我们有更低层次的algorithm来构build。
您将需要实施不太经常swap
自定义版本。 在C ++ 03中,为了避免代价高昂且抛出副本,通常需要高效的非抛出swap
,而且由于std::swap
使用两个副本,所以swap
通常必须自定义。 在C ++中, std::swap
使用move
,所以焦点转移到实现高效和非抛出移动构造函数和移动赋值运算符。 因为对于这些默认通常就好,这将比C ++ 03less得多。
一般来说,很难预测哪些习语会被使用,因为它们是通过经验创造的。 明年我们可以期待一个“有效的C ++ 11”,而三年之后才会有一个“C ++ 11编码标准”,因为必要的经验还没有出现。
我不知道它的名字,但是C ++ 03代码经常使用下面的结构作为缺失移动赋值的replace:
std::map<Big, Bigger> createBigMap(); // returns by value void example () { std::map<Big, Bigger> map; // ... some code using map createBigMap().swap(map); // cheap swap }
这样可以避免由于复制删除以及上面的swap
而造成的任何复制。
当我注意到一个使用C ++ 11标准的编译器不会再犯下面的代码:
std::vector<std::vector<int>> a;
为了包含运营商>>,我开始跳舞。 在早期版本中,人们不得不这样做
std::vector<std::vector<int> > a;
更糟糕的是,如果你必须debugging这个,你会知道这个错误信息是多么的可怕。
然而,我不知道这对你是否“显而易见”。
按价值回报不再是一个问题。 随着移动语义和/或返回值优化(编译器相关)编码function更自然,没有开销或成本(大部分时间)。