在C++ 11中不推荐使用哪些C++习惯用法?

Ala*_*jeu 192 c++ c++-faq c++11

有了新的标准,就会有新的做事方式,而且许多方式比旧方法更好,但旧的方式仍然很好.由于向后兼容的原因,新标准也没有正式弃用.所以剩下的问题是:

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

在回答这个问题时,你可以跳过诸如"使用自动变量"之类的显而易见的事情.

Sum*_*ant 173

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

我想我会在那里停下来!

  • 很好的答案,但我会从列表中击出`result_of`.尽管之前需要繁琐的`typename`,我认为`typename result_of <F(Args ...):: type`有时比`decltype(std :: declval <F>()(std ::)更容易阅读declval <Args>()...)`,并接受[N3436](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3436.html)他们都为SFINAE工作的工作文件(曾经是`result_of`没有提供的`decltype`的优势) (7认同)
  • Final不是关键字.http://en.cppreference.com/w/cpp/language/final (3认同)
  • 我想请注意,此主题链接自[此Microsoft页面](https://msdn.microsoft.com/library/vstudio/hh279654(v = vs.120).aspx)作为"更多信息"文章在C++语言的一般介绍中,但这个主题是一个高度专业化的!我可以建议一个简短的**"这个主题不适合C++新手!"**建议应该包含在主题的开头还是这个答案? (2认同)

How*_*ant 65

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

const A foo();
^^^^^
Run Code Online (Sandbox Code Playgroud)

这在C++ 98/03中几乎是无害的,甚至可能会发现一些看起来像的错误:

foo() = a;
Run Code Online (Sandbox Code Playgroud)

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

A a = foo();  // foo will copy into a instead of move into it
Run Code Online (Sandbox Code Playgroud)

所以请放松并编码:

A foo();  // return by non-const value
Run Code Online (Sandbox Code Playgroud)

  • 但是,现在可以通过使用函数的引用限定符来捕获可预防的错误.例如在上面的例子中定义`A&operator =(A o)&`而不是'A&operator =(A o)`.这些可以防止愚蠢的错误,并使类的行为更像基本类型,并且不会阻止移动语义. (8认同)

How*_*ant 61

只要你放弃0NULL赞成nullptr,就这样做!

在非通用代码中使用0NULL不是一个大问题.但是一旦你开始在泛型代码中传递空指针常量,情况就会迅速改变.当你传递0给一个template<class T> func(T) T推导为一个int而不是一个空指针常量.并且在此之后它不能被转换回空指针常量.如果只使用宇宙,这就会陷入一个根本不存在的问题的泥潭nullptr.

C++ 11不会弃用0,也不会NULL作为空指针常量.但你应该像编码那样进行编码.

  • @GrapschKnutsch:它是`std :: nullptr_t`. (4认同)

ken*_*ytm 38

安全bool成语explicit operator bool().

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

使用私有析构函数和虚拟继承模拟最终类class X final

  • 哇,我以前从未见过'安全布尔成语',看起来很恶心!我希望我在C++ 11之前的代码中永远不需要它... (2认同)

Kla*_*aim 24

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

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

一旦你使用带有完整C++ 11标准库的C++ 11编译器,你就没有理由不使用标准算法来构建你的.Lambda就是杀了它.

为什么?

在实践中(在我自己使用这种编写算法的方式之后),阅读用简单的单词构建的东西比用一些你必须解密以了解其含义的循环所做的更容易.也就是说,自动推导出lambda参数会有助于使语法更容易与原始循环相媲美.

基本上,使用标准算法制作的读取算法比隐藏循环的实现细节的单词要容易得多.

我猜想现在我们必须考虑更高级别的算法才能构建更低级别的算法.

  • 我没有看到带有lambda的`for_each`比基于范围的等效for循环更好,循环中lambda的内容.代码看起来或多或少相同,但lambda引入了一些额外的标点符号.您可以使用诸如`boost :: irange`之类的等价物将其应用于更多循环,而不仅仅是那些明显使用迭代器的循环.另外,基于范围的for循环具有更大的灵活性,因为你可以在需要时提前退出(通过`return`或`break`),而使用`for_each`你需要抛出. (10认同)
  • 其实有一个很好的借口.你正在使用[Boost.Range的](http://www.boost.org/doc/libs/1_48_0/libs/range/doc/html/range/reference/algorithms/introduction.html)算法,这些算法要好得多;) (8认同)
  • @SteveJessop在基于for循环的范围内`for_each`算法的一个优点是你_can't_ break`或`return`.也就是说,当你看到`for_each`时,你立即知道,而不是看着身体没有这样的棘手. (7认同)
  • @SteveJessop:即便如此,基于范围的`for`的可用性使得通常的`it = c.begin(),const end = c.end(); 它!=结束; ++它成语已经不存在了. (5认同)
  • @Klaim:具体来说,我比较的例如`std :: for_each(v.begin(),v.end(),[](int&i){++ i;});`with`for( auto&i:v){++ i; }`.我接受灵活性是双刃剑的(`goto`非常灵活,这就是问题所在).我不认为在`for_each`版本中不能使用`break`的约束补偿了它所要求的额外冗长 - 这里`for_each`的用户是IMO牺牲了实际的可读性和一种理论的便利性理论上,'for_each`原则上*更清晰,概念更简单.在实践中,它不是更清楚或更简单. (5认同)
  • @SteveJessop比以前更好的人解释了它,但基本上循环是循环,而for_each是"循环遍历'范围'的所有元素".在实践中(在我自己使用这种编写算法的方式之后),阅读用简单的单词构建的东西比用一些你必须解密以了解其含义的循环所做的更容易.也就是说,自动推导出lambda参数会有助于使语法更容易与原始循环相媲美,所以我理解你的感受. (3认同)

Phi*_*ipp 10

您需要swap更少地实现自定义版本.在C++ 03中,swap通常需要有效的非投掷以避免代价高昂且丢弃副本,并且由于std::swap使用两个副本,因此swap通常必须进行自定义.在C++中,std::swap使用move,因此焦点转移到实现高效和非投掷移动构造函数并移动赋值运算符.因为对于这些,默认通常很好,这将比C++ 03中的工作少得多.

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