用别处创建的对象填充 std::vector
Filling std::vector with objects created elsewhere
我正在尝试使用在函数中创建的对象填充 std::vector
,如下所示:
class Foo
{
public:
Foo() { std::cout << "Foo created!\n"; }
Foo(const Foo& other) { std::cout << "Foo copied!\n"; }
Foo(Foo&& other) { std::cout << "Foo moved\n"; }
~Foo() { std::cout << "Foo destroyed\n"; }
};
static Foo createFoo()
{
return Foo();
}
int main()
{
{
std::vector<Foo> fooVector;
fooVector.reserve(2);
fooVector.push_back(createFoo());
fooVector.push_back(createFoo());
std::cout << "reaching end of scope\n";
}
std::cin.get();
}
输出:
Foo created!
Foo moved
Foo destroyed
Foo created!
Foo moved
Foo destroyed
reaching end of scope
Foo destroyed
Foo destroyed
为什么 Foo
被销毁的次数比创建的次数多?我不明白这里发生了什么,我以为 Foo
会被复制,但是没有触发复制构造函数。
用别处创建的对象填充 std::vector
而不销毁它们的最佳方法是什么?
How can Foo be destroyed more times than it is created?
输出显示的创建次数与显示的破坏次数完全一样:
change -> cumulative total
Foo created! +1 -> 1
Foo moved +1 -> 2
Foo destroyed -1 -> 1
Foo created! +1 -> 2
Foo moved +1 -> 3
Foo destroyed -1 -> 2
reaching end of scope
Foo destroyed -1 -> 1
Foo destroyed -1 -> 0 all objects that were created are now destroyed
I thought that Foo would be copied, but the copy constructor is not triggered.
每次将右值传递给构造函数时。这就是为什么使用移动构造函数而不是复制构造函数的原因。
What is the best way to fill a std::vector with objects created elsewhere without them being destroyed?
好吧,不要破坏您在别处创建的对象...但通常您应该避免这样做,因为这通常是内存泄漏。
如果您在别处创建两个对象并在向量中创建两个对象,那么您最终会创建 4 个对象。如果您只想要两个对象,那么例如直接将对象创建到向量中而不是其他任何地方。例如:
fooVector.emplace_back();
fooVector.emplace_back();
当你这样做时
fooVector.push_back(createFoo());
首先 createFoo()
创建一个临时 Foo
对象,这就是您看到
的原因
Foo created!
然后,该对象 "moved" 进入向量,因为它是纯右值。这就是为什么你看到
Foo moved
现在向量中有一个对象,但也有已创建的临时对象,移动并不会删除该对象,它只是将其内部移动到向量中的对象中。一旦对象超出范围,您仍然需要销毁该对象,这发生在完整表达式的末尾,给您
Foo destroyed
输出。
移动语义的预期行为是从一个对象移动不会破坏它,而是破坏它,留下一个空的 shell。 shell 仍然必须在其范围的末尾处理,这意味着将照常调用其析构函数。该空对象应该在 "valid but unspecified state" 中:您仍然可以执行任何没有先决条件的操作(例如执行析构函数)。
如果您为具有移动语义的类型编写析构函数,您需要考虑到您可能正在销毁这样一个空对象。在这种情况下,析构函数可能不会做太多工作,但这取决于您的用例。
这最终维护了一个规则,即对于每个构造,都必须有一个相应的破坏,无论是哪种构造。
当你std::move(obj)
时,移动对象的状态应该是一个可以被销毁的新状态。这通常是通过将对象持有的数据传输到新对象(将使用 move ctor 构造)来实现的。最后,我们获取其内容的对象也将被销毁。
现在每个移动操作都会构造一个新对象并使旧对象处于待销毁状态,因此您有正确的输出 4 个构造(默认为 2 个 ctor,两个为移动 ctor)和相应的 4 个销毁.
当你使用 '}' 时,在 {} 之间没有 malloc 创建的每个局部变量都会被销毁,所以当你有一个破坏者时,它就会被调用。
查看此输出 ( ͡° ͜ʖ ͡°)
#include <iostream>
#include <vector>
#include <memory>
class Foo
{
public:
Foo() { std::cout << "Foo created!\n"; }
Foo(const Foo& other) { std::cout << "Foo copied!\n"; }
Foo(Foo&& other) { std::cout << "Foo moved\n"; }
~Foo() { std::cout << "Foo destroyed\n"; }
};
static Foo* createFoo()
{
return new Foo();
}
int main()
{
{
std::vector<std::unique_ptr<Foo>> fooVector;
fooVector.reserve(2);
fooVector.emplace_back(createFoo());
fooVector.emplace_back(createFoo());
std::cout << "reaching end of scope\n";
}
std::cin.get();
}
如果您是 C++ 爱好者并且关心性能,那么在 createFoo()
等函数内部创建对象的本地实例很少会引起共鸣。使用指针!
我正在尝试使用在函数中创建的对象填充 std::vector
,如下所示:
class Foo
{
public:
Foo() { std::cout << "Foo created!\n"; }
Foo(const Foo& other) { std::cout << "Foo copied!\n"; }
Foo(Foo&& other) { std::cout << "Foo moved\n"; }
~Foo() { std::cout << "Foo destroyed\n"; }
};
static Foo createFoo()
{
return Foo();
}
int main()
{
{
std::vector<Foo> fooVector;
fooVector.reserve(2);
fooVector.push_back(createFoo());
fooVector.push_back(createFoo());
std::cout << "reaching end of scope\n";
}
std::cin.get();
}
输出:
Foo created!
Foo moved
Foo destroyed
Foo created!
Foo moved
Foo destroyed
reaching end of scope
Foo destroyed
Foo destroyed
为什么 Foo
被销毁的次数比创建的次数多?我不明白这里发生了什么,我以为 Foo
会被复制,但是没有触发复制构造函数。
用别处创建的对象填充 std::vector
而不销毁它们的最佳方法是什么?
How can Foo be destroyed more times than it is created?
输出显示的创建次数与显示的破坏次数完全一样:
change -> cumulative total
Foo created! +1 -> 1
Foo moved +1 -> 2
Foo destroyed -1 -> 1
Foo created! +1 -> 2
Foo moved +1 -> 3
Foo destroyed -1 -> 2
reaching end of scope
Foo destroyed -1 -> 1
Foo destroyed -1 -> 0 all objects that were created are now destroyed
I thought that Foo would be copied, but the copy constructor is not triggered.
每次将右值传递给构造函数时。这就是为什么使用移动构造函数而不是复制构造函数的原因。
What is the best way to fill a std::vector with objects created elsewhere without them being destroyed?
好吧,不要破坏您在别处创建的对象...但通常您应该避免这样做,因为这通常是内存泄漏。
如果您在别处创建两个对象并在向量中创建两个对象,那么您最终会创建 4 个对象。如果您只想要两个对象,那么例如直接将对象创建到向量中而不是其他任何地方。例如:
fooVector.emplace_back();
fooVector.emplace_back();
当你这样做时
fooVector.push_back(createFoo());
首先 createFoo()
创建一个临时 Foo
对象,这就是您看到
Foo created!
然后,该对象 "moved" 进入向量,因为它是纯右值。这就是为什么你看到
Foo moved
现在向量中有一个对象,但也有已创建的临时对象,移动并不会删除该对象,它只是将其内部移动到向量中的对象中。一旦对象超出范围,您仍然需要销毁该对象,这发生在完整表达式的末尾,给您
Foo destroyed
输出。
移动语义的预期行为是从一个对象移动不会破坏它,而是破坏它,留下一个空的 shell。 shell 仍然必须在其范围的末尾处理,这意味着将照常调用其析构函数。该空对象应该在 "valid but unspecified state" 中:您仍然可以执行任何没有先决条件的操作(例如执行析构函数)。
如果您为具有移动语义的类型编写析构函数,您需要考虑到您可能正在销毁这样一个空对象。在这种情况下,析构函数可能不会做太多工作,但这取决于您的用例。
这最终维护了一个规则,即对于每个构造,都必须有一个相应的破坏,无论是哪种构造。
当你std::move(obj)
时,移动对象的状态应该是一个可以被销毁的新状态。这通常是通过将对象持有的数据传输到新对象(将使用 move ctor 构造)来实现的。最后,我们获取其内容的对象也将被销毁。
现在每个移动操作都会构造一个新对象并使旧对象处于待销毁状态,因此您有正确的输出 4 个构造(默认为 2 个 ctor,两个为移动 ctor)和相应的 4 个销毁.
当你使用 '}' 时,在 {} 之间没有 malloc 创建的每个局部变量都会被销毁,所以当你有一个破坏者时,它就会被调用。
查看此输出 ( ͡° ͜ʖ ͡°)
#include <iostream>
#include <vector>
#include <memory>
class Foo
{
public:
Foo() { std::cout << "Foo created!\n"; }
Foo(const Foo& other) { std::cout << "Foo copied!\n"; }
Foo(Foo&& other) { std::cout << "Foo moved\n"; }
~Foo() { std::cout << "Foo destroyed\n"; }
};
static Foo* createFoo()
{
return new Foo();
}
int main()
{
{
std::vector<std::unique_ptr<Foo>> fooVector;
fooVector.reserve(2);
fooVector.emplace_back(createFoo());
fooVector.emplace_back(createFoo());
std::cout << "reaching end of scope\n";
}
std::cin.get();
}
如果您是 C++ 爱好者并且关心性能,那么在 createFoo()
等函数内部创建对象的本地实例很少会引起共鸣。使用指针!