繁体   English   中英

一个类如何知道它不应该在析构函数中释放其分配的内存。 因为类是指针的指针?

[英]How can a class know, that it should not free its allocated memory in the destructor. Because the class is a pointee to a pointer?

一个类如何知道它不应该在析构函数中释放其分配的内存。 因为类是指针的指针?

一些不起作用的示例代码(未经测试)。 问题出在MyOtherClass的构造函数上。

class MyClass {
    ~MyClass() { free(...); } // free some vars, does not matter what.
};
class MyOtherClass {
    MyClass *m_ptr;
    MyOtherClass(MyClass pointee) {
        m_ptr = &pointee;
        // when this constructor is finished, the destructor of parameter "pointee" will be called.
        // and therefore the attribute "m_ptr" points to nothing. 
    }
};

MyClass有可能使用这样的东西吗?

class MyClass {
    bool i_am_a_pointee = false; // but how and where to assign this?
    ~MyClass() { 
        if (!i_am_a_pointee) { free(...); }
    }
};

目标是为多个不同的类创建一个类似容器的类。 但有指针。

代码:

class MyClassA {
    MyClassA() {}
    // here the pointer is cleared because that is required for my class. 
    // So when the var goes out of scope like in the constructor of "MyContainer(MyClassB)" all the vars will be deleted and therefore the pointer technically points to nothing.
    ~MyClassA() { free(...); } 
};
class MyClassB {
    MyClassB() {}
    // here the pointer is cleared because that is required for my class. 
    // So when the var goes out of scope like in the constructor of "MyContainer(MyClassB)" all the vars will be deleted and therefore the pointer technically points to nothing.
    ~MyClassB() { free(...); }
};
class MyContainer {
    MyClassA *m_class_a;
    MyClassB *m_class_b;
    MyContainer(MyClassA x) {
        m_class_a = &x // here the problem.
    }
    operator MyClassA() {
        return *m_class_a;
    }
    MyContainer(MyClassB x) {
        m_class_b = &x // here the problem.
    }
    operator MyClassB() {
        return *m_class_b;
    }
};
int main() {
    MyContainer container;
    MyClassA a;
    MyClassB b;
    container = a; // here the pointer is empty because of the problem.
    MyClassA a1 = container;
    container = b;
    MyClassB = container;
}
MyOtherClass(MyClass pointee) {
    m_ptr = &pointee;
}

MyContainer(MyClassA x) {
    m_class_a = &x // here the problem.
}

在这里,您按值获取pointee / x ,这意味着编译器将进行复制。 您需要定义一个有意义的复制构造函数才能使用指针。

然后您获取该参数的地址,这是一个本地堆栈变量。 在函数结束时,变量消失并且您的指针悬空。 无论您实现MyClassA多么正确,这都无法正常工作。

您需要一个指针或引用,以便您可以从调用者而不是局部变量获取对象的地址。 我建议使用智能指针。


永远不要存储原始指针。 有太多的方法可以把它搞砸。 当类是指针的唯一所有者时,请使用unique_ptr 当您需要将指针存储在多个位置时,请使用shared_ptr 如果不确定,例如返回用户可能存储或不存储的指针时,默认为shared_ptr

除了避免错误之外,这还简化了您的代码。 通常您不需要析构函数,因为unique_ptr / shared_ptr会为您处理清理工作。

一个类如何知道它不应该在析构函数中释放其分配的内存。 因为类是指针的指针?

简短的回答是,如果您想保存一个可能是也可能不是拥有指针的原始指针,那么您需要以某种方式跟踪该信息。 作为一种粗略的方法,您可以有一个名为delete_pointer_in_destructor的布尔成员变量,如果指针应该在析构函数中删除,则将其设置为 true,如果不应该删除,则将其设置为 false。 如果对象被分配在程序的其他地方,那么调用代码可能必须传入这个布尔值作为参数(连同指针)来告诉你的代码它需要做什么,因为没有办法让您的代码仅从原始指针就知道哪个设置是合适的。

OTOH 更好且更不容易出错的方法是完全避免原始拥有指针 - 仅按值存储对象(在这种情况下,您根本不需要调用newdelete ),或者(如果你不能这样做,例如因为你需要多态行为)那么至少使用像std::shared_ptrstd::unique_ptr这样的智能指针,因为它们将处理关于何时(或是否)调用 delete 的所有决定您,并免除您做出错误决定的风险。

MyOtherClass(MyClass pointee) {
    m_ptr = &pointee;
    // when this constructor is finished, the destructor of parameter "pointee" will be called.
    // and therefore the attribute "m_ptr" points to nothing. 
}

您应该尽量避免在对象被销毁之后保留指向对象的指针; 持有一个悬空指针是无用的并且会自找麻烦,因为任何实际使用悬空指针的尝试都会引发未定义的行为。 因此,上述代码的修复方法是在构造函数的末尾将m_ptr设置为 NULL(或者更好的是,一开始就不要将其设置为&pointee

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM