有可能在析构函数中知道r值引用正在被删除吗



我正在测试我自己的RAII指针实现,它(按设计(会做一些奇怪的事情。为了测试它,我制作了一个跟踪构造函数和析构函数的类,并确保所有内容都被删除和创建一次。

但我经常会收到一个错误,我删除了两次。奇怪,对吧。我发现了原因,您可以通过运行下面的示例来查看。

这不是最初生成它的代码,但它说明了这个问题。

struct ReportDelete
{
ReportDelete() = delete;
ReportDelete(const std::string& name) : name(name) { std::cout << "create " << name << "n"; }
ReportDelete(ReportDelete&& moveHere) : name(std::move(moveHere.name)) {}
ReportDelete& operator=(ReportDelete&& moveHere)
{
name = std::move(moveHere.name);
return *this;
}
ReportDelete(const ReportDelete&) = delete;
void operator=(const ReportDelete&) = delete;
std::string name;
~ReportDelete()
{
std::cout << "delete " << name << "n";
name = name + "-deleted";
}
};
int main(int argc, const char** argv)
{
std::vector<ReportDelete> moveTest;
moveTest.push_back(ReportDelete("test"));
}

此打印:

create test
delete
delete test

因此,析构函数仍然对移动的值进行调用。这并没有什么特别的坏处,但它使我无法正确测试创建/删除比率。

我实际的测试类在析构函数中这样做:

virtual ~Value() 
{
std::string error = name + " deleted twice!";
assertm(parent.values[fullname()] == false, error.c_str());
parent.values[fullname()] = true;
}

其中parent是跟踪是否在末尾删除值的类。但是,我怎么能知道这只是为Value&&运行的,应该被忽略呢?

我试过这个:

Value~() &&
{
std::cout << "rvalue destructor ignored...n";
}

但似乎你不可能有这样一个特殊的析构函数。

我怎么知道析构函数只在右值引用上被调用,因此我可以忽略它,而不将其作为真正的删除进行跟踪?

这与是否为r值引用调用析构函数无关。析构函数就是析构函数。一个对象正在被销毁。结束。物体的特定细节是无关紧要的。

ReportDelete& operator=(ReportDelete&& moveHere)
{
name = std::move(moveHere.name);
return *this;
}

这将从该对象的"已移动自"实例中移动name。但是,对象的移出实例仍然是一个有效的、现有的对象,并且在某个时刻它将被销毁

但是,您已离开其name成员。您的C++实现的结果是,从std::string移动的名称保留为空字符串。

当从中移出的对象被销毁时,其析构函数会打印一个空名称。这就是您看到的输出。

TLDR:您没有收到错误。您忽略的是,从中移出的对象仍然是一个有效的、现有的对象,并且它仍然会被销毁。它将是,在一个格式良好的C++程序中。事实上,因为在这种情况下,从中移动的物体是一个右值参考,它大大增加了从高轨道移动的物体即将被核武器击中的可能性。

最新更新