如何重置具有不可复制成员的c++类



我参考了如何在自己的成员函数中重置c++类,这里是一个简单的类。

class myclass
{
private:
some data...
std::mutex m_mutex;
public:
void clear() {
*this = {};
}
}
我不能写这样的代码,因为std::mutex有一个删除的拷贝赋值操作符

在c++中,我们有时会区分"逻辑状态"对象和"物理状态"的关系。逻辑状态——对象的状态,因为它可以通过它的公共API观察到。物理状态——是对象在物理内存中的表现方式。std::mutex通常不是逻辑状态的一部分,而是只存在于内部的"内务",即线程间访问同步。在下面的简化示例中可以明显看出这一点:

class Test {
int val = 10;
mutable std::mutex m;
public:
int getValue() const {
std::lock_guard l(m);
return val;
}
void setValue(int v) {
std::lock_guard l(m);
val = v;
}
};

这里对象的逻辑状态由变量val表示。我们甚至可以将等价操作符定义为:

bool operator ==(const Test& other) {
return getValue() == other.getValue();
}

但是如果我们想将函数getValue()声明为const,因为它应该是所有getter的情况,那么我们必须将互斥锁声明为mutable,否则我们会得到编译错误,因为它不可能锁定const互斥锁。

关键字mutable的使用通常很好地表明变量不是逻辑状态的一部分。但并不总是使用它,因为并不总是需要正确声明所有函数的constness。

好,现在回到你的问题。如果要重置"逻辑状态",然后你可以定义赋值操作符,就像我们的例子:

Test& operator=(const Test& other) {
setValue(other.getValue());
return *this;
}

然后你可以做你想要的重置功能:

void reset()
{
*this = {};
}

但是要做到这一点,你需要使用正确的所有函数和变量的constness,或者定义move赋值操作符,或者使用稍微不同的reset函数:

void reset()
{
Test t;
*this = t;
}

这是因为{}是右值,不能通过非const左值引用传递,所以我们需要使用左值引用,从而定义移动赋值操作符,使用const左值引用或传递左值来复制赋值操作符。

现在,如果出于某种原因你需要重置"物理状态"怎么办?对象,而不是逻辑状态。这也是可能的,但是你需要明白你在做什么,因为"重置"。如果互斥对象被锁定,则该互斥对象为未定义行为。无论如何,要重置物理状态,您只需要在同一个对象上调用析构函数和构造函数。析构函数可以直接调用,要调用构造函数,可以使用"placement new"。所以这个函数看起来像这样:

void physical_reset() {
this->~Test();
new (this) Test();
}

最新更新