一旦定义析构函数,我就会收到此错误,但如果没有编译成功,但我非常想定义析构函数来调试一些段错误。
class Socket {
private:
seastar::output_stream<char> socket;
public:
std::string peer;
public:
Socket() = default;
template <typename... Args>
explicit Socket(seastar::output_stream<char> &&s, std::string p) : socket(std::move(s)), peer(p) {}
~Socket() {
std::cout << "Socket has gone out of scope" << "\n";
}
seastar::future<> send(std::string message) {
co_await socket.write(message);
co_await socket.flush();
}
seastar::future<> close() {
co_await socket.close();
}
};
Run Code Online (Sandbox Code Playgroud)
编译失败,
error: object of type 'Socket' cannot be assigned because its copy assignment operator is implicitly deleted
connection->second.socketObj = std::move(socketObj);
^
./socketwrapper.h:44:46: note: copy assignment operator of 'Socket' is implicitly deleted because field 'socket' has a deleted copy assignment operator
seastar::output_stream<char> socket;
Run Code Online (Sandbox Code Playgroud)
有办法解决这个问题吗?
小智 5
这里的根本问题是“为什么当我显式使用时编译器试图使用复制赋值std::move()?”
让我们看一个简单、格式良好的示例:
struct MyStruct {
MyStruct()
: some_data(new int(12)) {}
MyStruct(const MyStruct& other)
: some_data(new int(*other.some_data)) {}
MyStruct& operator=(const MyStruct& rhs) {
delete some_data;
some_data = new int(*rhs.some_data);
return *this;
}
~MyStruct() {
delete some_data;
}
int * some_data;
};
MyStruct foo() {
return MyStruct();
}
int main() {
MyStruct a;
a = foo(); // <--- copy-assignment here, no choice.
}
Run Code Online (Sandbox Code Playgroud)
很明显,尽管这是 RValue 场景,但使用复制分配非常重要。
但为什么这个程序首先是格式良好的呢?这是一个移动分配设置,我没有移动分配运算符。编译器就不能给我一巴掌吗?问题是,在 C++11 和移动语义出现之前,它就已经是格式良好的,所以它必须保持正确的行为。
因此,在存在任何其他构造函数/析构函数/赋值运算符的情况下,如果不存在移动赋值/构造函数,则必须使用复制赋值/复制构造函数,以防万一它碰巧是编写的代码很久以前。
立即解决的方法是添加移动赋值运算符。到那时,它也可能有助于清理问题并完成完整的 5 规则。
class Socket {
private:
seastar::output_stream<char> socket;
public:
std::string peer;
public:
Socket() = default;
explicit Socket(seastar::output_stream<char> &&s, std::string p)
: socket(std::move(s)), peer(p) {}
Socket(Socket&&) = default;
Socket& operator=(Socket&&) = default;
// These are technically redundant, but a reader wouldn't know it,
// so it's nice to be explicit.
Socket(const Socket&) = delete;
Socket& operator=(const Socket&) = delete;
// ...
Run Code Online (Sandbox Code Playgroud)