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

时间:2017-12-12 09:46:04

标签: c++ c++11 constructor

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

  • 我有一个对象。让我们调用Victim,它包含指针变量,构造函数和析构函数。
  • 我有另一个对象,让我们调用Perpetrator,其构造函数接受一个Victim对象,并将指针变量复制到里面的具体变量中。
  • 我创建了Victim*,并使用new创建了对象,然后通过Perpetrator将其提供给Perpetrator(*victim)
  • Perpetrator的构造函数完成后,将调用Victim的析构函数并删除对象。

问题是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

3 个答案:

答案 0 :(得分:4)

Perpetrator (Victim victim) - 正在通过值传递对象。表示必须(复制)构造,然后在调用结束时销毁

事实上,根本不需要使用new。这样:

int main ()
{
  Victim poor;
  Perpetrator cruel(poor);

  cout << cruel.concrete << endl;
}

行为相似。你会看到两个结构和两个破坏。原始代码没有展示的第二个,因为你的例子泄露了。

答案 1 :(得分:0)

通过ref传递受害者:

struct Perpetrator
{
    double concrete;

    Perpetrator (Victim& victim)
    {
        concrete = *(victim.pointer);
    }
};

受害者将建造&amp;每次破坏一次。

答案 2 :(得分:0)

这是你想要实现的吗?

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
受害者的驱逐者被称为。
调用Perpetrator的析构函数。