指向类的C ++指针,释放类实例的调用函数,这是一种好的做法吗?

时间:2015-12-11 07:57:31

标签: c++ class pointers

我有一节课,我们称之为A。类A有两个子类,ab

我正在制作一个类A的指针:

A *pointer;

在程序中的某个时刻,我像这样初始化指针:

pointer = new a();

在其他方面,我运行了类A的函数:

pointer->function(&pointer);

此函数在类A内(因此所有子类都有它)。有可能在调用此函数时,我想更改指向另一个子类的指针,这是我尝试过的:

void A::function(A **pointer)
{
    if (something)
    {
        delete *pointer;
        *pointer = new b();
    }
}

虽然这很有效,但我真的很好奇,如果这是一个好习惯,我从对象内部调用delete并释放对象本身,这可能是未定义的行为,我很幸运它有效吗?我不理解这个吗?我是否比这更复杂?

4 个答案:

答案 0 :(得分:3)

是的,只要你小心,这是有效的。请参阅a question specifically about delete this上的更多讨论。

但是,与C ++中的其他内容一样,只要您小心,它们就是有效的,您最好找到另一种不易出错的解决方案。我建议你将代码重新编写成一个函数返回一个新指针,然后自动销毁旧指针(例如通过智能指针)。

有些事情:

struct A {
    static std::shared_ptr<A> function(std::shared_ptr<A>& ptr, int x) {
        if (x > 0)
            return std::make_shared<A>(x);
        else return ptr;
    }

    A(int _x): x(_x) {}

    int x;
};

另请注意,我将function()设为static,因为它无论如何都接受该对象作为其第一个参数。请参阅live on coliru

事实上,我不太喜欢shared_ptr这个解决方案,如果有人能更好地实现这种方法,我会很高兴知道。

答案 1 :(得分:1)

此代码有效(有关正确性的详细信息,请参阅this answer) 但这不是一个好习惯,因为其他开发人员可能会错过细微差别,使用其中一个成员函数会导致重建对象。
明确重建对象比隐藏成员函数更好。 或者只使用智能指针。

答案 2 :(得分:1)

作为一种设计我不喜欢指针突然指向另一个对象(不同类型),当它不清楚它发生时。可以说,由于OPs代码通过&pointer,它表明它可能会发生变化。但是,我更喜欢作业 - 我认为这更清楚。

我会尝试这样的事情:

int uglyGlobal = 1;  // don't try this at home...  ;-)

class A
{
public:
    int n;
    A() {n = uglyGlobal++; cout << "A cons for #" << n << endl;}
    virtual ~A() {cout << "A des for #" << n << endl;}
    unique_ptr<A> function(int something, unique_ptr<A> ptr);
};

class a : public A
{
public:
    a() {cout << "a cons" << endl;}
    ~a() override {cout << "a des" << endl;}
};
class b : public A
{
public:
    b() {cout << "b cons" << endl;}
    ~b() override {cout << "b des" << endl;}
};

unique_ptr<A> A::function(int something, unique_ptr<A> ptr)
{
    if (something == 0)
    {
        // Turn it into an A
        return unique_ptr<A>(new A);
    }
    else if (something == 1)
    {
        // Turn it into an a
        return unique_ptr<A>(new a);
    }
    else if (something == 2)
    {
        // Turn it into an b
        return unique_ptr<A>(new b);
    }
    else
        // Keep the current
        return ptr;
}

int main()
{
    cout << "Make A" << endl;
    unique_ptr<A> x (new A);

    cout << "1. call - turn A into a" << endl;
    x = x->function(1, move(x));

    cout << "2. call - turn a into b" << endl;
    x = x->function(2, move(x));

    cout << "3. call - turn b into another b" << endl;
    x = x->function(2, move(x));

    cout << "4. call - keep current b" << endl;
    x = x->function(3, move(x));

    cout << "Return from main" << endl;
    return 0;
}

输出结果为:

Make A
A cons for #1
1. call - turn A into a
A cons for #2
a cons
A des for #1
2. call - turn a into b
A cons for #3
b cons
a des
A des for #2
3. call - turn b into another b
A cons for #4
b cons
b des
A des for #3
4. call - keep current b
Return from main
b des
A des for #4

答案 3 :(得分:0)

通常,您必须确保调用function的每个执行路径都没有针对A或派生类(this的方法的堆栈帧无效)。 所以,这很危险。在MFC api编程中,这种情况发生在#34;通常&#34;在WM_NCDESTROY消息处理程序中。在其中您执行delete this之类的操作,但Windows确保WM_NCDESTROY是发送到窗口的最后一条消息。

我建议你改变一下A类的api并使用unique_ptr来处理内存:

#include <memory>

class A
{

public:

    std::unique_ptr<A> f()
    {
        return std::make_unique<A>();
    }
};

int main()
{
    auto p =  std::make_unique<A>();
    p = std::move(p->f());
    return 0;
}

通过这种方式,您可以将销毁从f()内部移动到p。

的分配