[英]Why does adding a destructor (even empty) break my struct that uses ref forwarding and collapsing to hold either a ref or copy of a value?
I am making a class to store a reference to an object if given an lvalue in the constructor and to store a copy if given an rvalue. 如果在构造函数中给出一个左值,我正在创建一个类来存储对象的引用,如果给出一个右值,则存储一个副本。 This is fine and compiles:
这很好并且编译:
template <typename obj_t>
struct holder
{
obj_t obj;
template <typename obj_ref_t>
holder(obj_ref_t && o)
: obj(std::forward<obj_ref_t>(o))
{}
};
template <typename obj_t>
holder<obj_t> make_held(obj_t && o) {
return holder<obj_t>(std::forward<obj_t>(o));
}
However, when I add a destructor (even an empty one) to the class, I get a compiler error: 但是,当我向类中添加析构函数(甚至是空的析构函数)时,我收到编译器错误:
Invalid instantiation of non-const reference of type "obj_t &" from an rvalue of type "holder<obj_t &>"
Why does adding a destructor somehow invoke a constructor call to create a wrapped object out of an already wrapped object? 为什么添加析构函数会以某种方式调用构造函数调用以从已包装的对象中创建包装对象?
A constructor template can never be a copy/move constructor 构造函数模板永远不能是复制/移动构造函数
template <typename obj_ref_t>
holder(obj_ref_t && o) // not a move constuctor
When the destructor definition is absent, you're making use of the implicitly defined move constructor for holder
. 当析构函数定义不存在时,您将使用隐式定义的
holder
移动构造函数。 The presence of a user defined destructor will suppress this implicit move constructor definition. 用户定义的析构函数的存在将抑制此隐式移动构造函数定义。
Now, the only remaining viable candidate is your converting constructor template above, but that doesn't work if obj_ref_t
is of type holder<T>
, this constructor is required to initialize the return value of make_held
. 现在,唯一剩下的可行候选者是你上面的转换构造函数模板,但是如果
obj_ref_t
的类型为holder<T>
,那么这obj_ref_t
,这个构造函数需要初始化make_held
的返回值。 So a call like this fails 所以像这样的电话会失败
auto h = make_held(42);
In short, don't define a destructor, or if you have to, define a move constructor. 简而言之,不要定义析构函数,或者如果必须,定义移动构造函数。
When defining constructor templates like the one you have, be aware that they might be preferred over move constructors in some cases. 在定义构造函数模板时,请注意在某些情况下它们可能比移动构造函数更受欢迎。 There are quite a few answers on SO about this, here's one that describes the problem and has a solution for constraining the constructor template.
关于这一点有很多答案, 这里有一个描述问题并且有一个约束构造函数模板的解决方案。
If you were to compile your code with a C++17 compiler, the above would compile even with a destructor definition because of guaranteed copy elision . 如果您要使用C ++ 17编译器编译代码,那么即使使用析构函数定义,上面也会编译,因为保证了复制省略 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.