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

Which C++ idioms are deprecated in C++11?

本文关键字:C++11 C++ 习惯 惯用法 哪些      更新时间:2023-10-16

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

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

在回答这个问题时,您可以跳过诸如"使用自动变量"之类显而易见的内容。

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

我想我就到此为止!

在某个时间点,有人认为应该按const值返回,而不是仅按值返回:

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

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

在非通用代码中,使用0NULL并不是什么大不了的事。但是,一旦您开始在泛型代码中传递空指针常量,情况就会很快发生变化。当您将0传递给template<class T> func(T)时,T将被推导为int,而不是空指针常量。在那之后,它不能转换回空指针常量。如果宇宙只使用nullptr,这些问题就根本不存在。

C++11不反对将0NULL作为空指针常量。但你应该像它那样编码。

安全布尔习语&rar;CCD_ 28。

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

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

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

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

一旦您使用了带有完整C++11标准库的C++11编译器,您就再也没有理由不使用标准算法来构建自己的了。Lambda杀了它。

为什么?

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

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

我猜现在我们有了较低级别的算法可以构建,所以只需要考虑更高级别的算法。

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

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

我不知道它的名称,但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;

更糟糕的是,如果你必须调试它,你就会知道由此产生的错误消息有多可怕。

I、 然而,不知道这对你来说是否"显而易见"。

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