提问人:Alan Baljeu 提问时间:2/16/2012 最后编辑:Toby SpeightAlan Baljeu 更新时间:1/14/2019 访问量:26231
哪些 C++ 习语在 C++11 中被弃用?
Which C++ idioms are deprecated in C++11?
问:
有了新的标准,就有了新的做事方式,很多都比旧方式好,但旧方式还是好的。同样明显的是,出于向后兼容性的原因,新标准并没有正式弃用太多。所以剩下的问题是:
哪些旧的编码方式肯定不如 C++11 风格,我们现在能做什么?
在回答这个问题时,你可以跳过“使用自动变量”等明显的事情。
答:
让您避免用 C++11 编写基本算法的一件事是 lambda 与标准库提供的算法相结合的可用性。
我现在正在使用这些算法,令人难以置信的是,您经常通过使用 count_if()、for_each() 或其他算法来告诉您想做什么,而不必再次编写该死的循环。
一旦你使用带有完整 C++11 标准库的 C++11 编译器,你就没有充分的理由不使用标准算法来构建你的。Lambda 只是杀死它。
为什么?
在实践中(在我自己使用过这种编写算法的方式之后),阅读用直截了当的单词构建的东西感觉比阅读一些你必须解密才能知道含义的循环要容易得多。也就是说,自动推导 lambda 参数将有很大帮助,使语法更容易与原始循环进行比较。
基本上,使用标准算法制作的读取算法要容易得多,因为单词隐藏了循环的实现细节。
我猜现在只需要考虑更高级别的算法,因为我们有较低级别的算法可以构建。
评论
for_each
boost::irange
return
break
for_each
for
it = c.begin(), const end = c.end(); it != end; ++it
for_each
break
return
for_each
std::for_each(v.begin(), v.end(), [](int &i) { ++i; });
for (auto &i : v) { ++i; }
goto
break
for_each
for_each
for_each
曾经有人认为,人们应该按价值返回,而不仅仅是按价值返回:const
const A foo();
^^^^^
这在 C++98/03 中基本上是无害的,甚至可能捕获了一些看起来像这样的错误:
foo() = a;
但是 C++11 中禁止返回 by,因为它抑制了移动语义:const
A a = foo(); // foo will copy into a instead of move into it
因此,只需放松并编码即可:
A foo(); // return by non-const value
评论
A& operator=(A o)&
A& operator=(A o)
您需要较少地实现自定义版本。在 C++03 中,通常需要高效的非抛出以避免成本高昂的抛出副本,并且由于使用两个副本,因此通常必须自定义。在 C++ 中,使用 ,因此重点转移到实现高效且非抛出的移动构造函数和移动赋值运算符上。由于对于这些,默认值通常很好,因此这将比 C++03 中的工作量少得多。swap
swap
std::swap
swap
std::swap
move
一般来说,很难预测会使用哪些习语,因为它们是通过经验创造的。我们可以期待明年的“有效的C++11”,而“C++11编码标准”则要在三年内才能出现,因为必要的经验还没有。
评论
只要你能放弃并赞成,就这样做!0
NULL
nullptr
在非泛型代码中,使用 or 并不是什么大问题。但是,一旦开始在泛型代码中传递 null 指针常量,情况就会迅速改变。当你传递给 a 时,会被推断为 a 而不是 null 指针常量。之后它不能转换回空指针常量。这陷入了问题的泥潭,如果宇宙只使用,这些问题根本不存在。0
NULL
0
template<class T> func(T)
T
int
nullptr
C++11 不弃用 和 作为空指针常量。但是你应该像它一样编码。0
NULL
评论
std::nullptr_t
0
NULL
安全的布尔成语→。explicit operator bool()
私有复制构造函数 (boost::noncopyable) →X(const X&) = delete
使用私有析构函数和虚拟继承→模拟最终类class X final
评论
- 最终类:C++11 提供了说明符以防止类派生
final
- C++11 lambda 大大减少了对命名函数对象(函子)类的需求。
- 移动构造函数:由于对右值引用的一流支持,不再需要工作的神奇方式。
std::auto_ptr
- Safe bool:前面已经提到过了。C++11 的显式运算符避免了这个非常常见的 C++03 习惯用语。
- 收缩适应:许多 C++11 STL 容器都提供了成员函数,这应该消除了与临时交换的需要。
shrink_to_fit()
- 临时基类:一些旧的 C++ 库使用这个相当复杂的习惯用语。有了移动语义,就不再需要它了。
- 类型:安全枚举枚举在 C++11 中非常安全。
- 禁止堆分配:语法是一种更直接的说法,表示显式拒绝特定功能。这适用于防止堆分配(即,对于成员)、防止复制、分配等。
= delete
=delete
operator new
- 模板化类型定义:C++11 中的别名模板减少了对简单模板化类型定义的需求。但是,复杂类型生成器仍然需要元函数。
- 一些数值编译时计算(如斐波那契)可以很容易地使用广义常量表达式进行替换
result_of
:类模板的用法应替换为 。我认为在可用时使用。result_of
decltype
result_of
decltype
- 类内成员初始值设定项保存键入,以便使用默认值对非静态成员进行默认初始化。
- 在新的 C++ 中,代码应该重新定义为 ,但请参阅 STL 的演讲以了解他们为什么决定反对它。
NULL
nullptr
- 表达式模板狂热者很高兴在 C++11 中使用尾随返回类型函数语法。不再有 30 行长返回类型!
我想我会就此打住!
评论
result_of
typename
typename result_of<F(Args...)::type
decltype(std::declval<F>()(std::declval<Args>()...)
decltype
result_of
我不知道它的名称,但 C++ 代码经常使用以下构造来替换缺少的移动赋值:
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
评论
map
map
当我注意到使用 C++11 标准的编译器不再出现以下代码错误时:
std::vector<std::vector<int>> a;
据说包含操作员>>,我开始跳舞。在早期版本中,必须这样做
std::vector<std::vector<int> > a;
更糟糕的是,如果你不得不调试它,你就会知道由此产生的错误消息是多么可怕。
但是,我不知道这对你来说是否“显而易见”。
评论
按值返回不再是问题。通过移动语义和/或返回值优化(依赖于编译器),编码函数更加自然,没有开销或成本(大多数时候)。
评论
下一个:默认函数参数的有效表达式
评论
auto_ptr