0

假设启用了正常的编译器优化,以下存在多少副本发生/对象:

std::vector<MyClass> v;
v.push_back(MyClass());

如果不完全是 1 个对象创建和 0 个复制,我能做些什么(包括更改MyClass)来实现这一点,因为在我看来,这就是真正需要的全部?

4

4 回答 4

4

如果 的构造函数MyClass有副作用,则在 C++03 中不允许省略副本。这是因为作为副本源的临时对象已绑定到引用(的参数push_back)。

如果 的复制构造函数MyClass没有副作用,则允许编译器根据“as-if”规则对其进行优化。我认为确定它是否真的通过“正常优化”这样做的唯一明智方法是检查发出的代码。不同的人有不同的想法什么是正常的,并且给定的编译器可能对MyClass. 我的猜测是,这相当于编译器(或链接器)是否内联了所有可见的内容。如果是,那么它可能会优化,如果不是,那么它不会。因此,即使构造函数代码的大小也可能是相关的,别管它做了什么。

所以我认为你可以做的主要事情是确保默认和复制构造函数MyClass都没有副作用并且可以内联。如果它们不可用,那么编译器当然会假设它们可能有副作用并会进行复制。如果链接时优化对您来说是一个正常的编译器选项,那么您不必做太多事情就可以使它们可用。否则,如果它们是用户定义的,则在定义MyClass. 您可能能够摆脱具有某些副作用的默认构造函数:如果效果不依赖于与向量元素的地址不同的临时地址,那么“as-if”仍然适用。

在 C++11 中,你有一个动作(如果它有副作用,同样也不能被忽略),但你可以使用它v.emplace_back()来避免它。移动将调用移动构造函数MyClass,否则将调用复制构造函数,并且我上面所说的关于“as-if”的所有内容都适用于移动。emplace_back()调用无参数构造函数来构造向量元素(或者如果你将参数传递给emplace_back任何与这些参数匹配的构造函数),我认为这正是你想要的。

于 2012-11-27T10:05:58.580 回答
1

你的意思是:

std::vector<MyClass> v;
v.push_back(MyClass());

没有任何。临时将导致调用 push_back 的移动版本。即使是移动结构也很可能会被省略。

于 2012-11-27T09:55:54.247 回答
1

如果您有 C++11 编译器,则可以使用emplace_back构造向量末尾的元素,需要零份。

于 2012-11-27T10:00:53.320 回答
0

在 C++03 中,您将拥有一个构造和一个副本,以及临时的销毁。

如果你的编译器支持 C++11 并且 MyClass 定义了一个移动构造函数,那么你就有一个构造和一个移动。

正如 Timbo 所提到的,您还可以使用 emplace_back 来避免移动,即就地构建的对象。

于 2012-11-27T10:07:36.340 回答