简体   繁体   English

为什么添加析构函数(甚至为空)会破坏我的结构,该结构使用ref转发和折叠来保存值的ref或副本?

[英]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.

相关问题 当lvalue-ref-arg和rvalue-ref-arg作为相同的forwarding-ref类型传递时,为什么它不起作用? - Why does it not work when an lvalue-ref-arg and an rvalue-ref-arg are passed as the same forwarding-ref type? 为什么我的 std::ref 没有按预期工作? - Why does my std::ref not work as expected? l值ref和r值ref以及non-ref类型的完美转发可变参数模板? - Perfect forwarding variadic templates of l-value ref and r-value ref and non-ref types? Rvalue ref和完美转发 - Rvalue ref and perfect forwarding 为什么 ranged for 循环将 value 隐式转换为 ref? - Why does ranged for loop converts value to ref implicitly? 为什么`boost :: multi_array_ref`的析构函数是非虚拟的? - Why is destructor of `boost::multi_array_ref` non-virtual? 为什么 shared_ptr ref count 的 impl 包含指向实际指向类型的指针? - Why does the impl of shared_ptr ref count hold a pointer to the actual pointed type? 为什么左值会明确选择左值引用重载而不是转发引用重载? - Why is an lvalue-ref overload unambiguously chosen over a forwarding-ref overload for an lvalue? 为什么我的const ref无效? - Why my const ref becomes invalid? 完美转发,为什么析构函数会被调用两次? - Perfect forwarding, why does the destructor get called twice?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM