gpt4 book ai didi

c++ - 显式删除从不使用的复制构造函数给出编译错误

转载 作者:行者123 更新时间:2023-11-30 01:10:27 25 4
gpt4 key购买 nike

我正在实现一个 SizeTag 方法,该方法将获取一个大小值并保留左值引用。

一切正常,在此代码中的目的是使用 T&& 构造函数。

但是,如果我显式删除复制构造函数,编译器会报错:

#include <cstdint>
#include <type_traits>
#include <utility>

template <typename T = std::uint64_t>
class SizeTag {
public:
using size_type = std::uint64_t;
using Type = std::conditional_t<std::is_lvalue_reference<T>::value, const size_type&, size_type>;
inline const Type& get() const { return _size; }

SizeTag(T&& sz) : _size(std::forward<T>(sz)) { }
SizeTag& operator = (const SizeTag&) = delete;

SizeTag(const SizeTag&) = delete; // No error if this line removed

private:
Type _size;
};

template <typename T>
SizeTag<T> make_size_tag(T&& t) {
return std::forward<T>(t);
}

int main()
{
int a = 9;
make_size_tag(a);
}

为什么会这样?在这种情况下,永远不应调用复制构造函数。

最佳答案

函数make_size_tag返回 SizeTag<T>按值(value)。

让我们回顾一下如何 function returning by value作品:

  • 有一个临时对象,通常称为返回值对象
  • 案例return expression; :
    • 表达式复制初始化返回值对象。
    • 这是一个复制省略上下文。
  • 案例return { zero_or_more_items }; :
    • 大括号列表复制列表初始化返回值对象。
  • 如果调用代码通过函数调用初始化了一个变量,那么返回值对象就是初始化器。 (具体的初始化形式可能因调用代码而异)。对于对象的初始化,这也是一个复制省略上下文。

在您的代码中,make_size_tag(a)推导T (make_size_tag 的参数)到int& ,因为这是一个完美的转发场景。

make_size_tag的实例化为此 T看起来,展开后std::forward :

SizeTag<int&> make_size_tag(int& t)
{
return t;
}

因为static_cast<int&>(t)t 相同, 自 t已经是 int 类型的左值.


如前所述,这段代码copy-initializes返回值对象。所以代码现在的行为有点像:

SizeTag<int&> temp_rv = t;

因为 t不是 SizeTag , copy-initialization 的定义是this等同于:

SizeTag<int&> temp_rv = SizeTag<int&>(t);

这显然调用了复制/移动操作来初始化 temp_rv来自 SizeTag<int&> 类型的临时文件.尽管此拷贝会被复制省略所省略,但可访问的复制/移动构造函数必须存在。


Jarod42 建议的解决方案,将大括号放在返回表达式周围,是有效的,因为等效的初始化现在是 copy-list-initialization :

SizeTag<int&> temp_list_rv { t };

初始化temp_list_rv使用 SizeTag<int&>(int&)构造函数。


注意;您的代码有一个单独的错误:因为 Typeconst uint64_t & , _size 的初始化来自 int创建一个临时的,当 SizeTag 时被销毁构造函数完成;因此标签返回一个悬空引用。 clang 对此发出警告,但 g++ 没有。

要解决此问题:您需要更改 TypeT&相同所以它直接绑定(bind)到 a ,例如:

using size_type = typename std::remove_reference<T>::type;

或制作_size不能作为引用。后者似乎会破坏标签的全部用途,因此您可能需要重新考虑一下您的设计。

要避免生成这个悬空引用的可能性,请更改 const size_type &size_type &在 conditional_t。然后编译器(假设您没有使用 MSVC)会指出问题。

关于c++ - 显式删除从不使用的复制构造函数给出编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37581041/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com