将对象的指针提供给构造函数会导致对象被破坏

Providing a pointer of an object to a constructor causes object to be destructed

本文关键字:对象 指针 构造函数      更新时间:2023-10-16

我在一个项目中看到了一种奇怪的行为。情况如下:

  • 我有一个对象。让我们调用包含指针变量的Victim,一个构造函数和破坏者。
  • 我有另一个对象,让我们调用Perpetrator,其构造函数接受Victim对象,然后将指针变量复制到内部的混凝土变量。
  • 我创建一个Victim*,并使用new创建对象,然后通过Perpetrator(*victim)
  • 将其提供给Perpetrator
  • Perpetrator的构造函数完成时,Victim的destructor被称为并删除对象。

问题是Victim的唯一副本,即poor在施工过程中被完全破坏。通过delete poor在末尾整理程序将导致双重错误。

在C 98/11,GCC 4.8.5、7.X和LLVM Clang中,行为是一致的,因此必须很好地定义它。这种行为叫什么,它的语义是什么?

我的理论是,因为constructor接受了一个具体的对象,因此被视为复制,因此在完成constructor/function时会破坏它。

由于我赞美PoC||GTFO,这是代码:

澄清:该示例是故意编写的,因为它是一个更复杂但非裸露和管理良好的数据结构复杂的简化模型。删除所有必要的位,使其看起来像是一个可怕的代码。在真实代码中,Victim是一个长期的数据存储,Perpetrator是用于处理上述数据的临时存储变量。

#include <iostream>
using namespace std;
struct Victim
{
  double* pointer;
  Victim ()
  {
    this->pointer = new double(42.2);
  }
  ~Victim ()
  {
    cout << "Destructor of the Victim is called." << endl;
    delete this->pointer;
  }
};
struct Perpetrator
{
  double concrete;
  Perpetrator (Victim victim)
  {
    concrete = *(victim.pointer);
  }
};

int main ()
{
  Victim* poor = new Victim();
  Perpetrator cruel(*poor);
  cout << cruel.concrete << endl;
}

样本输出:

./destructor_test 
Destructor of the Victim is called.
42.2

Perpetrator (Victim victim)-通过value 传递对象。意味着它必须是(复制)构造,然后在呼叫完成时被破坏。

实际上,根本不需要使用new。这个:

int main ()
{
  Victim poor;
  Perpetrator cruel(poor);
  cout << cruel.concrete << endl;
}

的行为类似。您将看到两个结构和两个破坏。您的原始代码不显示第二个,因为您的示例泄漏。

通过参考:

通过受害者
struct Perpetrator
{
    double concrete;
    Perpetrator (Victim& victim)
    {
        concrete = *(victim.pointer);
    }
};

受害者将构建&amp;

每次破坏。

这是您想实现的目标吗?

using namespace std;
struct Victim
{
  double* pointer;
  Victim ()
  {
    this->pointer = new double(42.2);
  }
  ~Victim ()
  {
    cout << "Destructor of the Victim is called." << endl;
    delete this->pointer;
  }
};
struct Perpetrator
{
  double concrete;
  Perpetrator (Victim *victim)
  {
    concrete = *(victim->pointer);
  }
    ~Perpetrator ()
  {
    cout << "Destructor of the Perpetrator is called." << endl;
  }
};

int main ()
{
  Victim* poor = new Victim();
  Perpetrator cruel(poor);
  cout << cruel.concrete << endl;
  delete poor;
}

输出:42.2
受害者的毁灭者被称为。
调用肇事者的驱动器。