gpt4 book ai didi

c++ - 为什么拥有析构函数会使类不可复制?

转载 作者:行者123 更新时间:2023-12-02 09:50:28 25 4
gpt4 key购买 nike

我有一个不编译的简单程序

#include <future>

class Foo
{
public:
~Foo();
std::future<int> f;
};

Foo getFoo()
{
return Foo();
}

int main()
{
Foo b = getFoo();
}

我想这很有道理。 Foo不可复制,因为 future不可复制。
 In function 'Foo getFoo()':
13:16: error: use of deleted function 'Foo::Foo(const Foo&)'
4:7: note: 'Foo::Foo(const Foo&)' is implicitly deleted because the default definition would be ill-formed:
4:7: error: use of deleted function 'std::future<_Res>::future(const std::future<_Res>&) [with _Res = int]'
In file included from 2:0:
/usr/include/c++/4.9/future:686:7: note: declared here
future(const future&) = delete;
^
In function 'int main()':
18:20: error: use of deleted function 'Foo::Foo(const Foo&)'

我不明白的是为什么在删除析构函数时它会编译:
#include <future>

class Foo
{
public:
//~Foo();
std::future<int> f;
};

Foo getFoo()
{
return Foo();
}

int main()
{
Foo b = getFoo();
}

这个析构函数不是默认生成的吗?它对可复制/可移动的类有什么影响?

最佳答案

隐式生成的副本构造函数被定义为已删除,因为您的类包含一个std::future,该副本不可复制。这意味着您的类(class)在任何情况下均不可复制。

但是,它可能是可移动的。通常,您显示的示例也可以使用move构造函数,但是当您手动声明一个析构函数时,隐式的move构造函数不会被声明,这使得第一个示例中的Foo也不可移动,而在第二个示例中则不可移动。

正如@Ayxan在问题下的评论中提到的那样,由于C++ 17,两个示例都可以编译,因为尽管在第一个示例中Foo不可移动,但由于C++ 17强制性复制省略规则适用,因此只有在您的示例中直接构建为Foo的一种Foo b。不会存在临时的Foo对象,因此该类不需要是可复制的或可移动的。

通常,如果您具有自定义析构函数,则应始终手动实现复制/移动构造函数和赋值运算符。那就是rule of 3/5。尽管自C++ 11起已弃用了如果存在用户声明的析构函数的情况下,对复制操作的隐式声明,该语言当前不对复制操作强制执行此规则。但是,如果存在用户声明的析构函数,则语言不会通过不隐式声明移动操作来强制执行移动操作的规则。

自定义析构函数不是经常需要的,因此您可能首先不应该声明它。如果您需要声明它,例如您需要将其设置为virtual(在这种情况下,应将其默认设置为virtual ~Foo() = default),然后可以默认移动操作:

Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;

但是,如果析构函数具有一个自定义定义,该定义中确实包含可以实际执行某些工作的语句,则您可能必须自己以适当的语义实现这些方法,以免在移动类时不会遇到问题。

关于c++ - 为什么拥有析构函数会使类不可复制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60016301/

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