哪些C++习惯用法在C++11中被弃用?

有了新的标准,就有了新的做事方法,许多方法比旧的方法更好,但旧的方法仍然很好。同样明显的是,由于向后兼容性的原因,新标准并没有正式弃用太多。所以剩下的问题是:

哪些旧的编码方式肯定不如C++11风格,我们现在可以做什么呢?

在回答这个问题时,您可以跳过“使用自动变量”等显而易见的内容。

25977 次浏览

避免在C++11中编写基本算法的原因之一是lambdas与标准库提供的算法相结合的可用性。

我现在正在使用它们,并且令人难以置信的是,您经常通过使用count_if()、for_each()或其他算法来告诉您想要做什么,而不必再次编写该死的循环。

使用带有完整C++11标准库的C++11编译器时,你再也没有理由不使用标准算法来构建你的。拉姆达,杀了它。

为什么?

在实践中(在我自己使用这种方式编写算法之后),感觉读一些用简单的单词构建的东西要比读一些必须解密才能知道意思的循环容易得多。也就是说,自动推导lambda参数将有助于使语法更容易与原始循环进行比较。

基本上,用标准算法编写的阅读算法要容易得多,因为单词隐藏了循环的实现细节。

我猜现在只有更高层次的算法需要考虑,因为我们有更低层次的算法可以构建。

有一次,有人认为应该通过const值来返回,而不是仅仅通过值来返回:

const A foo();
^^^^^

这在C++98/03中基本上是无害的,甚至可能捕获了一些看起来像这样的错误:

foo() = a;

但是在C++11中禁止按const返回,因为它禁止移动语义:

A a = foo();  // foo will copy into a instead of move into it

所以只要放松和编码:

A foo();  // return by non-const value

您需要较少地实现swap的自定义版本。在C++03中,通常需要有效的非抛出swap,以避免代价高昂的抛出副本,并且由于std::swap使用两个副本,因此通常必须自定义swap。在C++中,std::swap使用move,因此重点转移到实现高效且非抛出的移动构造函数和移动赋值操作符上。由于这些默认设置通常很好,这将比C++03中的工作量少得多。

一般来说,很难预测哪些习语会被使用,因为它们是通过经验创造出来的。我们可以期待“有效的C++11 ”可能在明年,而“ C++11编码标准”只在三年内,因为必要的经验还没有出现。

一旦您可以放弃0NULL,而选择nullptr,请立即这样做!

在非泛型代码中,使用0NULL并不是什么大问题。但是,一旦您开始在泛型代码中传递空指针常量,情况就会迅速改变。当您将0传递给template<class T> func(T)时,T被推导为int,而不是空指针常量。并且在此之后不能将其转换回空指针常量。如果宇宙只使用nullptr,这些问题就不会存在。

C++11不反对将0NULL作为空指针常量。但您应该编写代码,就像它确实存在一样。

安全布尔习语&rarr;explicit operator bool()

私有复制构造函数(boost:noncopyable)&rarr;X(const X&) = delete

用私有析构函数和虚继承模拟final类&rarr;class X final

  1. 最后一节课:C++11提供final说明符以防止类派生
  2. C++11lambdas大大减少了对命名函数对象(仿函数)类的需求。
  3. 移动构造函数:由于对右值引用的一流支持,不再需要std::auto_ptr的神奇工作方式。
  4. 安全布尔:这在前面提到过。C++11的显式操作符避免了这个非常常见的C++03习惯用法。
  5. 收缩到适合:许多C++11STL容器提供了shrink_to_fit()成员函数,这应该消除了与临时函数交换的需要。
  6. 临时基类:一些旧的C++库使用这种相当复杂的习惯用法。有了移动语义,就不再需要它了。
  7. _,ABC_0枚举在C++11中是非常安全的。
  8. 禁止堆分配= delete语法是一种更为直接的表示明确拒绝特定功能的方式。这适用于防止堆分配(即,成员operator new=delete)、防止复制、分配等。
  9. 模板化的typedef:C++11中的别名模板减少了对简单模板化类型定义的需求。但是,复杂类型生成器仍然需要元函数。
  10. 一些数值编译时计算,如斐波那契,可以很容易地用广义常数表达式来代替。
  11. result_of:类模板result_of的使用应替换为decltype。我认为result_of在可用时使用decltype
  12. 类内成员初始值设定项保存使用默认值对非静态成员进行默认初始化的键入。
  13. 在新的C++11代码_中,ABC_0应重新定义为nullptr,但请参阅STL的谈话,以了解他们决定反对它的原因。
  14. 表达式模板狂热者很高兴拥有C++11中的尾随返回类型函数语法。不再有30行的长返回类型!

我想我会停在那里!

我不知道它的名称,但C++03代码经常使用以下构造来替换丢失的移动赋值:

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;

更糟糕的是,如果你曾经调试过这个程序,你就会知道由此产生的错误消息有多可怕。

然而,我不知道这对你来说是否“显而易见”。

按值返回不再是问题。通过移动语义和/或返回值优化(依赖于编译器),编码函数更加自然,没有开销或成本(大多数情况下)。