什么时候在 C++ 中调用要移动到的对象的析构函数?
When is the destructor of an object that is being moved to called in C++?
我有一些 class A
,我可以不使用任何东西或 std::function
来构造它们。在破坏时应该调用给定的函数(如果有的话)。我的问题是对象在创建并由我的 getSomeA()
函数返回后立即被销毁,该函数在它应该被调用之前调用 std::function
。传递给构造函数的函数应该只被调用一次。一些示例代码:
#include <iostream>
#include <functional>
static void testFunction(const std::string& msg)
{
std::cout << "TestFunction: " << msg << "\n";
}
class A {
public:
A(void) = default;
A(const std::function<void()>& onDestroy) :
onDestroy(onDestroy)
{ }
~A(void)
{
if (onDestroy) onDestroy();
else std::cout << "in dtor but no onDestroy was set\n";
}
private:
std::function<void()> onDestroy;
};
A getSomeA(void)
{
return A(std::bind(testFunction, "the A that was created inside getSomeA"));
}
int main(void)
{
A b1;
std::cout << "After creating b1\n";
b1 = getSomeA();
std::cout << "After reassigning b1\n";
std::cout << "Here the program works with b1...\n";
}
程序输出
After creating b1
TestFunction: the A that was created inside getSomeA
After reassigning b1
Here the program works with b1...
TestFunction: the A that was created inside getSomeA
所以函数在它应该被调用之前被调用了(在 int main() 的末尾)。
添加移动构造函数和赋值运算符后,一切正常:
A(A&& other) :
onDestroy(std::exchange(other.onDestroy, nullptr))
{ }
A& operator=(A&& other)
{
onDestroy = std::exchange(other.onDestroy, nullptr);
return *this;
}
程序输出
After creating b1
in dtor but no onDestroy was set
After reassigning b1
Here the program works with b1...
TestFunction: the A that was created inside getSomeA
实际问题:第一次销毁对象在哪里调用testFunction?在 getSomeA()
或赋值之前但在 getSomeA()
?
中创建对象之后的主函数中
所有编辑:我试图用一个小时来解决我的问题,但由于我不知道 C++ 中的 move/copy 语义,这对我来说非常困难。
在第一个版本中,作为返回 getSomeA
中构造的对象的一部分,对象第一次被销毁。它的 return
语句有效地构造了一个临时对象,然后将其分配给 main
的 b1
。如果忽略函数返回的过程,则事件顺序为:
A <temporary object>(std::bind( ... )
b1=<temporary object>
<temporary object gets destroyed>
此时绑定函数被调用,因为临时对象被销毁。临时对象是一个完全被欺骗的对象,具有授予它的所有权利和特权。包括析构函数。
等等,还有更多! b1
是原始对象的完美 bit-by-bit 副本,在它被销毁之前具有绑定功能。因此,当 b1
被销毁时,该函数将再次被调用。
这是Rule Of Three的间接结果。当一个对象拥有一个资源,并且必须保持对该资源的独占所有权时,您需要提供一个副本 and/or 移动构造函数 and 和赋值运算符来准确说明在那种情况下应该发生什么。
P.S。这些规则随着 C++17 的保证复制省略而略有变化,但基本概念仍然相同。
我有一些 class A
,我可以不使用任何东西或 std::function
来构造它们。在破坏时应该调用给定的函数(如果有的话)。我的问题是对象在创建并由我的 getSomeA()
函数返回后立即被销毁,该函数在它应该被调用之前调用 std::function
。传递给构造函数的函数应该只被调用一次。一些示例代码:
#include <iostream>
#include <functional>
static void testFunction(const std::string& msg)
{
std::cout << "TestFunction: " << msg << "\n";
}
class A {
public:
A(void) = default;
A(const std::function<void()>& onDestroy) :
onDestroy(onDestroy)
{ }
~A(void)
{
if (onDestroy) onDestroy();
else std::cout << "in dtor but no onDestroy was set\n";
}
private:
std::function<void()> onDestroy;
};
A getSomeA(void)
{
return A(std::bind(testFunction, "the A that was created inside getSomeA"));
}
int main(void)
{
A b1;
std::cout << "After creating b1\n";
b1 = getSomeA();
std::cout << "After reassigning b1\n";
std::cout << "Here the program works with b1...\n";
}
程序输出
After creating b1
TestFunction: the A that was created inside getSomeA
After reassigning b1
Here the program works with b1...
TestFunction: the A that was created inside getSomeA
所以函数在它应该被调用之前被调用了(在 int main() 的末尾)。
添加移动构造函数和赋值运算符后,一切正常:
A(A&& other) :
onDestroy(std::exchange(other.onDestroy, nullptr))
{ }
A& operator=(A&& other)
{
onDestroy = std::exchange(other.onDestroy, nullptr);
return *this;
}
程序输出
After creating b1
in dtor but no onDestroy was set
After reassigning b1
Here the program works with b1...
TestFunction: the A that was created inside getSomeA
实际问题:第一次销毁对象在哪里调用testFunction?在 getSomeA()
或赋值之前但在 getSomeA()
?
所有编辑:我试图用一个小时来解决我的问题,但由于我不知道 C++ 中的 move/copy 语义,这对我来说非常困难。
在第一个版本中,作为返回 getSomeA
中构造的对象的一部分,对象第一次被销毁。它的 return
语句有效地构造了一个临时对象,然后将其分配给 main
的 b1
。如果忽略函数返回的过程,则事件顺序为:
A <temporary object>(std::bind( ... )
b1=<temporary object>
<temporary object gets destroyed>
此时绑定函数被调用,因为临时对象被销毁。临时对象是一个完全被欺骗的对象,具有授予它的所有权利和特权。包括析构函数。
等等,还有更多! b1
是原始对象的完美 bit-by-bit 副本,在它被销毁之前具有绑定功能。因此,当 b1
被销毁时,该函数将再次被调用。
这是Rule Of Three的间接结果。当一个对象拥有一个资源,并且必须保持对该资源的独占所有权时,您需要提供一个副本 and/or 移动构造函数 and 和赋值运算符来准确说明在那种情况下应该发生什么。
P.S。这些规则随着 C++17 的保证复制省略而略有变化,但基本概念仍然相同。