在c++中将临时插入向量

Pushing temporary into vector in c++

本文关键字:插入 向量 c++      更新时间:2023-10-16

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

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

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

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

如果MyClass的复制构造函数没有副作用,则允许编译器根据"好像"规则对其进行优化。我认为,要确定它是否真的使用了"正常优化",唯一明智的方法就是检查发出的代码。不同的人对什么是正常有不同的想法,给定的编译器可能对MyClass的细节很敏感。我的猜测是,这意味着编译器(或链接器)是否内联了所有可见的内容。如果它做到了,那么它可能会优化,如果它没有,那么它就不会。因此,即使是构造函数代码的大小也可能是相关的,别管它做什么。

因此,我认为您可以做的主要事情是确保MyClass的默认构造函数和复制构造函数都没有副作用,并且可以内联。如果它们不可用,那么编译器当然会认为它们可能有副作用,并进行复制。如果链接时间优化对您来说是一个正常的编译器选项,那么您不必做太多工作来使它们可用。否则,如果它们是用户定义的,则在定义MyClass的头文件中执行此操作。默认构造函数可能会产生某些副作用:如果效果不取决于临时的地址与向量元素的地址不同,那么"好像"仍然适用。

在C++11中,您有一个移动(如果它有副作用,也不能忽略它),但您可以使用v.emplace_back()来避免这种情况。move会调用MyClass的move构造函数(如果它有),否则会调用copy构造函数,我上面所说的"好像"都适用于moves。emplace_back()调用无参数构造函数来构造矢量元素(或者,如果您将参数传递给emplace_back,那么无论哪个构造函数都匹配这些参数),我认为这正是您想要的。

您的意思是:

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

无。临时将导致调用push_back的移动版本。即使是搬迁施工也很可能被取消。

如果您有C++11编译器,您可以使用template_back在向量末尾构造元素,无需任何副本。

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

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

正如Timbo所提到的,您也可以使用template_back来避免移动,即在原地构建对象。