[英]Why is emplace_back() behaving like this?
#include <iostream>
#include <vector>
class Base
{
private:
static int m_count;
public:
Base()
{
std::cout << " Base created. Count = " << ++m_count << std::endl;
}
~Base()
{
std::cout << " Base destroyed. Count = " << --m_count << std::endl;
}
void sayHello() const
{
std::cout << " Base says hello" << std::endl;
}
};
int Base::m_count = 0;
int main()
{
{
std::vector< Base > vBase;
vBase.emplace_back ( Base() ); // <- Why does ~Base() get called here
vBase[0].sayHello(); // <- Why is this function accessible after call to dtor
}
return 0;
}
Program output...程序输出...
Base created. Count = 1
Base destroyed. Count = 0
Base says hello
Base destroyed. Count = -1
In the call vBase.emplace_back ( Base() );
在调用vBase.emplace_back ( Base() );
you first create a Base
object.您首先创建一个Base
对象。 The vector creates another Base
in place and the resources owned by the first Base
are then moved into the new one.该向量在原地创建另一个Base
,然后将第一个Base
拥有的资源移动到新的Base
中。 The first base is then deleted.然后删除第一个碱基。 Inside your vector you now have a moved constructed Base
which is why the call to sayHello()
works.在您的向量中,您现在有一个移动的构造Base
,这就是调用sayHello()
起作用的原因。
What you probably want to do is to let emplace_back
actually construct the object, in place without creating a temporary object manually.您可能想要做的是让emplace_back
实际构造对象,而无需手动创建临时对象。 You do that by only supplying the arguments needed to construct a Base
.您只需提供构建Base
所需的参数即可做到这一点。 Like so:像这样:
vBase.emplace_back();
You're missing the point of emplace.你错过了安位点。 Emplace functions construct the object in-place from the given arguments, as opposed to eg push_back
which copy-constructs it from a pre-existing object. Emplace 函数从给定的参数就地构造对象,而不是例如push_back
从预先存在的对象复制构造它。 You should have written vBase.emplace_back()
which constructs the object inside the vector in-place with no constructor arguments (ie default constructed).您应该已经编写了vBase.emplace_back()
,它在没有构造函数参数的情况下就地构造向量内部的对象(即默认构造)。
As it stands you're effectively default constructing a Base
object via Base()
, passing it to emplace, which calls the constructor taking a Base
object (ie the move constructor), copying it, and then the original ie the Base()
object is destroyed.就目前而言,您实际上默认通过Base()
构造一个Base
对象,将其传递给 emplace,它调用构造函数获取Base
对象(即移动构造函数),复制它,然后复制原始对象,即Base()
对象被摧毁。
Its copy is still in the vector, which is why you can still access it.它的副本仍在向量中,这就是您仍然可以访问它的原因。 What was destroyed was the temporary.被破坏的是临时的。 The second destructor call is the copy being destroyed when the vector goes out of scope.第二个析构函数调用是当向量超出范围时被销毁的副本。
So you're basically just doing the same thing as push_back
.所以你基本上只是在做与push_back
相同的事情。
You're not including the objects created by move and copy constructors in your counter, nor are you logging the calls.您没有在计数器中包含由移动和复制构造函数创建的对象,也没有记录调用。 If you make changes to your logging to fix the Rule of Three/Five violation, you'll see this:如果您对日志进行更改以修复违反三/五规则的规则,您将看到以下内容:
#include <typeinfo>
#include <iostream>
/// noisy
///
/// A class logs all of the calls to Big Five and the default constructor
/// The name of the template parameter, received as if by call
/// to `typeid(T).name()`, is displayed in the logs.
template<typename T>
struct noisy
{
noisy& operator=(noisy&& other) noexcept { std::cout << "MOVE ASSIGNMENT<" << typeid(T).name() << ">(this = " << this << ", other = " << &other << ")\n"; return *this; }
noisy& operator=(const noisy& other) { std::cout << "COPY ASSIGNMENT<" << typeid(T).name() << ">(this = " << this << ", other = " << &other << ")\n"; return *this; }
noisy(const noisy& other) { std::cout << "COPY CONSTRUCTOR<" << typeid(T).name() << ">(this = " << this << ", other = " << &other << ")\n"; }
noisy(noisy&& other) noexcept { std::cout << "MOVE CONSTRUCTOR<" << typeid(T).name() << ">(this = " << this << ", other = " << &other << ")\n"; }
~noisy() { std::cout << "DESTRUCTOR<" << typeid(T).name() << ">(this = " << this << ")\n"; }
noisy() { std::cout << "CONSTRUCTOR<" << typeid(T).name() << ">(this = " << this << ")\n"; }
};
#include <iostream>
#include <vector>
class Base : public noisy<Base>
{
public:
void sayHello() const
{
std::cout << "Base says hello" << "(this = " << this << ")" << std::endl;
}
};
int main()
{
{
std::vector< Base > vBase;
vBase.emplace_back ( Base() ); // <- Why does ~Base() get called here
vBase[0].sayHello(); // <- Why is this function accessible after call to dtor
}
return 0;
}
Output:输出:
CONSTRUCTOR<4Base>(this = 0x7fff300b580f)
MOVE CONSTRUCTOR<4Base>(this = 0x18a6c30, other = 0x7fff300b580f)
DESTRUCTOR<4Base>(this = 0x7fff300b580f)
Base says hello(this = 0x18a6c30)
DESTRUCTOR<4Base>(this = 0x18a6c30)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.