如何切换到C ++ 11?


35

我已经用C ++编程了一段时间了,但是大多数事情都围绕着C ++的低级功能。我的意思是主要使用指针和原始数组。我认为这种行为被称为将C ++与类一起使用。尽管如此,我最近才第一次尝试C。我很惊讶地发现C#和Java之类的语言如何在便捷的标准库类(如字典和列表)中隐藏这些细节。

我知道C ++标准库也有许多容器,例如矢量,映射和字符串,而C ++ 11仅通过具有std :: array和ranged循环来增加了它。

我如何最好地学习如何利用这些现代语言功能以及哪些功能适合哪些时间?如今,C ++中的软件工程大部分都不需要人工进行内存管理吗?

最后,我应该使用哪个编译器来充分利用新标准?Visual Studio具有出色的调试工具,但即使VS2012似乎也具有糟糕的C ++ 11支持。


2
我会说将VS2012的C ++ 11支持称为“糟糕”有点夸张,但肯定会更好(缺少初始化列表对于测试/玩具代码特别烦人)。但是请注意,他们宣布他们将独立于VS的其余部分独立提供编译器更新,因此我想我们可以希望在2013
Martin Ba

3
起初,我认为建议学习C ++ 11会很奇怪,但是看到您仍然陷入C-Class-Class领域 ……十年前,我读了Koenig / Moo的Accelerated C ++。到我实际上已经在做模板元编程的时候(我只是读它做评论),但仍然感觉像是一个启示。(从那以后,我一直以此为基础来教授C ++。)本书源于C With Classes,可以为您展示一种全新的语言,您不知道自己可以使用的语言。它只有250页,然后您可以快速前进到C ++ 11特定的内容,但是IMO这是值得的一步。
2012年

4
g++ -std=c++11
fredoverflow

Answers:


50

首先,一些经验法则:

  • 使用std::unique_ptr作为一个无开销的智能指针。您不必经常烦恼原始指针。std::shared_ptr在大多数情况下同样是不必要的。首先,对共享所有权的渴望常常背叛了缺乏所有权的思想。

  • 使用std::array静态长数组和std::vector动态。

  • 广泛使用通用算法,尤其是:

    • <algorithm>
    • <numeric>
    • <iterator>
    • <functional>
  • 使用autodecltype()无论他们受益可读性。尤其是,当您要声明事物,但是您不需要关心的类型(例如迭代器或复杂的模板类型)时,请使用auto。当您要根据其他事物的类型声明一个事物时,请使用decltype()

  • 尽可能使类型安全。当您拥有对特定事物强制执行不变式的断言时,该逻辑可以集中在一种类型中。这并不一定会导致任何运行时开销。不用说,(T)x应避免使用C样式的强制类型转换(),而应使用更显式(且可搜索!)的C ++样式的强制类型转换(例如static_cast)。

  • 最后,知道规则三:

    • 析构函数
    • 复制构造函数
    • 赋值运算符

    通过添加move构造函数和move赋值运算符,已成为五个规则。并大致了解右值引用以及如何避免复制。

C ++是一种复杂的语言,因此很难描述如何最好地使用所有这些语言。但是,良好的C ++开发实践并没有从C ++ 11根本改变。与手动内存管理相比,您仍然应该首选内存管理的容器-智能指针使轻松高效地做到这一点。

我要说的是,现代C ++实际上基本上没有手动内存管理功能-C ++内存模型的优点是它是确定性的,而不是手动的。可预测的释放使性能更可预测。

对于编译器,G ++和Clang在C ++ 11功能方面都具有竞争力,并且迅速弥补了它们的不足。我不使用Visual Studio,所以我既不能支持也不可以反对。

最后,注意事项std::for_each:一般情况下避免使用。

transformaccumulateerase- remove_if是好老的功能mapfoldfilter。但是for_each它比较笼统,因此意义不大- 除了循环外,它不表达任何其他意图。除此之外,它在与基于范围的情况下使用的情况相同for,并且即使在无点使用的情况下,在语法上也较重。考虑:

for (const auto i : container)
    std::cout << i << '\n';

std::for_each(container.begin(), container.end(), [](int i) {
    std::cout << i << '\n';
});

for (const auto i : container)
    frobnicate(i);

std::for_each(container.begin(), container.end(), frobnicate);

6
这些经验法则有约束力的原则吗?似乎是不错的建议清单,但是...作为一个外人,通过Google提出了这个问题,您的答案将如何帮助我以有原则的方式学习C ++ 11,并在不将自己缠在C ++轴上的情况下使用它?
罗伯特·哈维

3
列表为+1,但我有个小问题:当(正确地)警告std::for_each我时,我希望基于for循环的范围可以替代plain更好for
Fabio Fracassi 2012年

@FabioFracassi:糟糕。我写平原与对比std::for_each,不是基于范围的。我已将其删除以避免混淆。
乔恩·普迪

1
如果不是,我会更新std::for_each()。当您拥有lambda时,它肯定比传统for循环好。对于基于范围的for循环,情况可能并非如此,但是您并未编写“基于范围的for循环”。
2012年

@sbi:在我看来,术语“ for循环”包括“基于范围的for循环”。我编辑了更多的解释和一个例子来澄清,谢谢。
乔恩·普迪

12

作为起点:

  • 停止使用char*字符串。使用std::stringstd::wstring只是看着您的代码变得更短,更易读,更安全
  • 停止使用C样式的数组(用声明的东西[ ]),然后使用std::vector或其他一些适当的容器类。关于std::vector它的好处是,它知道自己的长度,在超出范围时会清理其内容,很容易进行迭代,并且在添加更多项时会变得更大。但是,还有其他一些集合可能会更适合您的情况。
  • 使用std::unique_ptr-并std::move立即学习。因为这可能会导致一些不可复制的对象,懒惰可能偶尔送你走向std::shared_ptr-你可能有一些真正的使用情况std::shared_ptr,以及
  • auto在声明依赖于先前声明的迭代器和类型时使用(例如,您先前声明了某物的向量,现在您在声明某物,请使用auto
  • for_each尽可能使用算法和“原始”,因为它使其他人不必仔细阅读循环即可得出结论,实际上您正在遍历整个集合等。如果编译器支持“ range”,则应将其用于之上for_each。了解琐碎的算法调用一样iotagenerateaccumulatefind_if等等。
  • 使用lambda-它们是利用算法的简单方法。他们还打开了更多的大门。

不要对使用哪种编译器太费力。VS2012中缺少C ++ 11支持的“糟糕,糟糕”是没有可变参数模板(是的,您正要使用可变参数模板)并且{}初始化程序不存在。我也想要这样做,但是我将不停止使用有用的开发工具来代替它。

拥抱之后std::,要做的第二件事是开始思考RAII。随时有

  • 开始行动
  • 从开始动作中得到的一系列动作
  • 即使在异常情况下也需要执行的清理操作

然后,您将拥有一个构造函数,多个成员函数和一个析构函数。写一个可以帮您解决这个问题的课程。您甚至不必编写ctor和dtor。将a shared_ptr作为类的成员变量放置是RAII的一个示例-您无需编写内存管理代码,但是当实例超出范围时,将发生正确的事情。将这种想法扩展到涵盖诸如关闭文件,释放句柄,锁等之类的内容,并且代码将变得更加简单和小巧(同时消除泄漏)。

如果你感到非常有信心,净化printf赞成cout,摆脱宏(的#define东西),并开始学习一些“先进成语”像PIMPL。我在Pluralsight 有一个完整的课程,您可以使用他们的免费试用版观看。


2
我喜欢您对他不久不使用可变参数模板的讽刺,但我认为缺少统一初始化会丢失对于日常编程非常重要的东西。
2012年

等不及要初始化列表了……等着找出何时才能得到它们……
Kate Gregory

VS2012中的另一个重要不足是“右值引用v3”,即自动生成的移动构造函数和移动分配。
C64先生2012年

3

我如何最好地学习如何利用这些现代语言功能以及哪些功能适合哪些时间?

通过编程。经验是最好的学习方式。

C ++ 11具有许多新功能(自动,右值,新的智能指针-仅举几例)。最好的开始就是开始使用它们,并在可能的时候和发现有趣的文章时阅读它们。

如今,C ++中的软件工程大部分都不需要人工进行内存管理吗?

这取决于您需要做什么。大多数应用程序可以摆脱智能指针的束缚,而不必理会内存管理。仍然有一些应用程序无法如此轻松地摆脱(例如,如果由于某种原因需要新的放置或自定义内存分配器)。

如果需要使用Qt,则必须使用其规则进行内存管理。

我应该使用哪个编译器来充分利用新标准?

您拥有的支持最新标准的东西:

但是没有编译器支持所有功能。


-7

我的大学仍在使用C ++进行教学。我已经用C ++编程了5年,现在我是一名研究生。当然,现在我正在使用很多Java,Ruby等。我真的建议您不要太着急像Java这样的语言。以我的经验和观点,仅次于C ++的低级功能。您应该研究诸如使用C / C ++进行通用编程的主题,例如制作模板类,模板函数,重写运算符,虚拟方法,智能指针。对于面向对象的设计部分,C ++具有很多功能,而Java没有,例如多继承。继承既强大又危险。C ++中面向对象设计的实现级别也是一个很好的话题。进程间通信,线程在C ++中也很重要。

用于编译器和调试器。我知道Visual Studio很棒。但我真的建议您学习GDB,Valgrind和Make still,并精通这些工具。微软很棒,但是它为您做了很多事情。作为一名学生,您确实需要学习Microsoft也为您做的那些事情。对于编译器,G ++优于GNU。

毕竟,经过这么多年,我真的感到,最重要的事情是诸如原始数组之类的低级功能。向量实际上只是一个动态数组。这些是我的建议,有些东西可能太主观,只要采纳您认为正确的方法即可。


6
这如何回答这个问题?问题不是一般地学习C ++,而是切换到C ++ 11。
洛克·马蒂
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.