假设正常的编译器优化已启用,以下内容中存在多少个副本/对象:
std::vector<MyClass> v;
v.push_back(MyClass());
如果它不完全是1个对象创建和0个复制,我可以做什么(包括MyClass
中的更改)来实现这一点,因为在我看来,这是真正需要的所有内容?
答案 0 :(得分:4)
如果MyClass
的构造函数有副作用,那么在C ++ 03中不允许删除副本。那是因为作为副本源的临时对象已绑定到引用(参数push_back
)。
如果MyClass
的复制构造函数没有副作用,则允许编译器在“as-if”规则下对其进行优化。我认为确定它是否实际上通过“正常优化”这样做的唯一合理方法是检查发出的代码。不同的人有不同的想法是正常的,给定的编译器可能对MyClass
的细节敏感。我的猜测是,这相当于编译器(或链接器)是否内联了所有内容。如果它确实那么它可能会优化,如果没有,那么它就不会优化。因此,即使构造函数代码的大小也可能是相关的,不管它做什么。
所以我认为你可以做的主要是确保MyClass
的默认和复制构造函数都没有副作用,并且可以内联。如果它们不可用,那么编译器当然会认为它们可能有副作用并且会进行复制。如果链接时优化是一个正常的编译器选项,那么您不必做太多工作就可以使它们可用。否则,如果它们是用户定义的,则在定义MyClass
的头文件中执行此操作。您可能能够使用具有某些副作用的默认构造函数:如果效果不依赖于临时的地址与vector元素的地址不同,则“as-if”仍然适用。
在C ++ 11中你有一个动作(如果它有副作用同样不能被忽略),但你可以使用v.emplace_back()
来避免这种情况。移动会调用MyClass
的移动构造函数,如果它有一个,否则复制构造函数,以及我上面提到的关于“as-if”的所有内容都适用于移动。 emplace_back()
调用no-args构造函数来构造vector元素(或者如果你将参数传递给emplace_back
,那么无论构造函数与那些args匹配),我认为这正是你想要的。
答案 1 :(得分:1)
你的意思是:
std::vector<MyClass> v;
v.push_back(MyClass());
无。临时将导致调用push_back的移动版本。即使是移动建设也很可能会被淘汰。
答案 2 :(得分:1)
如果你有一个C ++ 11编译器,你可以使用emplace_back在向量的末尾构造元素,必要的零拷贝。
答案 3 :(得分:0)
在C ++ 03中,您将拥有构造和副本,以及临时的破坏。
如果你的编译器支持C ++ 11并且MyClass定义了一个移动构造函数,那么你有一个构造和一个移动。
正如Timbo所提到的,你也可以使用emplace_back来避免移动,对象就地构建。