是否有任何方法可以在堆栈内存中将函数中创建的对象的所有权传递给函数外部而不使用复制构造?
通常,编译器会自动对函数栈上的对象调用析构。因此,如果我们想创建一个类的对象(可能带有一些特定的参数),我们如何避免浪费大量资源从临时对象复制?
这是一种常见的情况:
while(...){
vectors.push_back(createObject( parameter ));
}
所以当我们想在迭代中用一些参数创建对象,并将它们压入vector
时,正常的值传递方式会花费很多时间来复制对象. 我不想在堆内存上使用指针和new
对象,因为用户很可能会忘记删除
它们,从而导致内存泄漏。
嗯,智能指针也许是一个解决方案。但是……不那么优雅,我想。呵呵
有没有办法应用右值引用
和 move
语义来解决这个问题?
最佳答案
通常,按值返回对象将不会复制对象,因为编译器应该进行(命名的)返回值优化,从而省略复制。
通过这种优化,返回对象的空间是从调用上下文(外部堆栈框架)分配的,并且对象是直接在那里构造的。
在您的示例中,编译器将在 createObject()
的上下文中为对象分配空间。叫做。由于此上下文是 std::vector<T>.push_back()
的(未命名)参数成员函数,这用作右值引用,因此 push_back()
按值将通过将对象 move (而不是复制)到 vector 中来使用它。这是可能的,因为如果生成的对象是可 move 的。否则,将发生复制。
总而言之,每个对象都将被创建,然后 move (如果可 move )到 vector 中。
下面是一个示例代码,更详细地展示了这一点:
#include <iostream>
#include <string>
#include <vector>
using Params = std::vector<std::string>;
class Object
{
public:
Object() = default;
Object(const std::string& s) : s_{s}
{
std::cout << "ctor: " << s_ << std::endl;
}
~Object()
{
std::cout << "dtor: " << s_ << std::endl;
}
// Explicitly no copy constructor!
Object(const Object& other) = delete;
Object(Object&& other)
{
std::swap(s_, other.s_);
std::cout << "move: traded '" << s_ << "' for '" << other.s_ << "'" << std::endl;
}
Object& operator=(Object other)
{
std::swap(s_, other.s_);
std::cout << "assign: " << s_ << std::endl;
return *this;
}
private:
std::string s_;
};
using Objects = std::vector<Object>;
Object createObject(const std::string& s)
{
Object o{s};
return o;
}
int main ()
{
Objects v;
v.reserve(4); // avoid moves, if initial capacity is too small
std::cout << "capacity(v): " << v.capacity() << std::endl;
Params ps = { "a", "bb", "ccc", "dddd" };
for (auto p : ps) {
v.push_back(createObject(p));
}
return 0;
}
请注意 class Object
明确禁止复制。但要使其工作, move 构造函数必须可用。
关于何时可以(或将)发生复制省略的详细摘要可用 here .
关于c++ - 如何将对象的所有权传递给函数外部,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45712257/