【问题标题】:Deleting a pointer in destructor C++在析构函数 C++ 中删除指针
【发布时间】:2018-05-17 08:56:26
【问题描述】:

我正在使用库中的一个类。设为A,它有一个字符指针“token”

我的代码:

void someFunction()
{
    A a;
    cout<<a.token;
    anotherFunction(a);
    cout<<a.token;  //  line 4: now token became invalid [1]
}

void anotherFunction(A copyOfA);
{
   //  doing something
}  //  on exit destructor of copyofA will be called

[1]为什么会失效:A类如下:

class A
{
    char *token;
    public:
    A()
    {
        token = GetRandomToken();   // GetRandomToken will return a 'new Char' array
    }
    ~A()
    {
        if(token != NULL)
        {
            delete[] token;    // it is A's responsibility to delete the memory it created
            token = NULL;
        }
    }
};

anotherFunction 中调用 copyOfA 的析构函数 token 被删除。 所以在第 4 行,token 无效,因为 a.token 和 copyOfA.token 都指向同一个地址。

有什么解决办法,在以下情况:

案例 1:class A 在给定的库中:所以我无法修改它。

案例2:如果我可以修改class A:处理这个问题的好方法是什么?

我知道,如果通过传递引用调用 anotherFunction,我就不会遇到这个问题。但是如果我必须在某个时候保留对象的副本怎么办?

在此处查看示例代码:https://ideone.com/yZa4k4

【问题讨论】:

  • class A 不遵循rule of 3/5。你不能安全地复制它
  • 唯一的解决方法是永远不要创建副本。您只能拥有一个实例并传递指向它的引用或指针。
  • 您可以通过正确的实现将A 类包装在另一个类B 中,并且永远不要直接使用A。问题是:你打算复制A 做什么?复制token指出的内容?或者两个实例应该共享token
  • 把图书馆扔掉,因为它太糟糕了。如果你可以修改它,只需给它适当的复制语义
  • 为了呼应@PasserBy,把图书馆扔掉,因为如果作者弄错了,那么谁知道他们还弄错了什么?

标签: c++ oop pointers


【解决方案1】:

如果你不能修改class A,那么你应该避免复制它。我认为最安全的方法是动态分配class A的对象:

void anotherFunction(std::shared_ptr<A> aPtr)
{
    // please also note that in your case token is PRIVATE
    std::cout << aPtr->token << std::endl;
}

std::shared_ptr<A> aPtr(new A);
std::cout << aPtr->token << std::endl;
anotherFunction(aPtr);

或者如果你坚持堆栈分配,你应该把anotherFunction签名改为:

void anotherFunction(const A& a)
{
    std::cout << a.token << std::endl;
}

通过 const 引用传递你的论点(避免复制构造函数)。

现在,如果您可以修改您的class A,您应该应用the rule of three/five/zero,因为您有非平凡的析构函数。这样做的懒惰方法是将其他构造函数声明为已删除(然后,就像在您的示例中一样,您不能复制您的 A 对象,但您也可以保证没有人会尝试这样做):

class A
{
    public:
    // for this example purpose I made token PUBLIC, but it is a bad idea in general
    char *token;
    A()
    {
        token = GetRandomToken();   // GetRandomToken will return a 'new Char' array
    }
    ~A()
    {
        if(token != NULL)
        {
            delete[] token;    // it is A's responsibility to delete the memory it created
            token = NULL;
        }
    }
    A(const A& other) = delete;
    A(A&& other) = delete;
};

或者,如果你不是懒惰的,你实际上可以考虑如何将内存从一个对象中的token 指针复制到另一个对象——这取决于你如何实现它。这取决于GetRandomToken 的要求和实现。

【讨论】:

    【解决方案2】:

    如果您的示例准确,则 class A 没有正确的复制构造函数,因此会删除两个实例的令牌。 这会导致双重删除,因为第一个实例中的指针没有改变。

    【讨论】:

      猜你喜欢
      • 2014-12-30
      • 2018-01-03
      • 2012-03-13
      • 2018-09-12
      • 2013-10-01
      • 2021-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多