基类指针:在哪里使用 new 和 delete

Base class pointer: where to use new and delete

本文关键字:new delete 指针 在哪里 基类      更新时间:2023-10-16

我想知道我应该在以下类结构中在哪里使用newdelete

#include <iostream>
class StateBase {
public:
    StateBase( int val ) : m_stateInfo(val) {}
    virtual ~StateBase() {}
    virtual int getState() = 0;
protected:
    int m_stateInfo;
};
class StateImpl1 : public StateBase {
public:
    StateImpl1() : StateBase( 1 ) {}
    ~StateImpl1() {}
    int getState() {
        //std::cout << "stateimpl:" << m_stateInfo << std::endl;
        return m_stateInfo;
    }
};
class DeviceBase {
public:
    DeviceBase( StateBase* pState ) : mp_state( pState ) {}
    ~DeviceBase() {} // TODO or delete here? but then it's a bit asymmetric...
    virtual void work() = 0;
protected:
    StateBase* mp_state;
};
class DeviceImpl1 : public DeviceBase {
public:
    DeviceImpl1() : DeviceBase( new StateImpl1() ) {}
    // TODO d'tor here? but then base is left without valid ptr to "mp_state"
    ~DeviceImpl1() { delete mp_state; }
    void work() {
        std::cout << "DeviceImpl1 work: state = " << mp_state->getState() << std::endl;
    }
};

int main() {
    DeviceImpl1 impl1;
    impl1.work();
    return 0;
}

我猜,将delete放在基类中是不对称的,而且可读性较差。 在派生类(调用new(中使用 delete 会使基类具有无效指针(如果只是很快,但它不干净(。

  • 在派生类中使用它,将 PTR 设置为 NULL 并检查基类中NULL的指针可能是一个选项
  • 也许整个设计有缺陷? 如果是这样:还有什么替代方案?

更新: 我不能使用现代C++因为它必须使用交叉编译器

使用 unique_ptr 管理所有权/生存期/内存:

#include <iostream>
#include <memory>
#include <utility>
class StateBase {
public:
    StateBase( int val ) : m_stateInfo(val) {}
    virtual ~StateBase() {}
    virtual int getState() = 0;
protected:
    int m_stateInfo;
};
class StateImpl1 : public StateBase {
public:
    StateImpl1() : StateBase( 1 ) {}
    ~StateImpl1() {}
    int getState() {
        return m_stateInfo;
    }
};
class DeviceBase {
public:
    DeviceBase( std::unique_ptr<StateBase> ) : mp_state( std::move(pState) ) {}
    virtual ~DeviceBase() {}
    virtual void work() = 0;
protected:
    std::unique_ptr<StateBase> mp_state;
};
class DeviceImpl1 : DeviceBase {
public:
    DeviceImpl1() : DeviceBase( std::make_unique<StateImpl1>() ) {}
    ~DeviceImpl1() = default;
    void work() {
        std::cout << "DeviceImpl1 work: state = " << mp_state->getState() << std::endl;
    }
};

int main() {
    DeviceImpl1 impl1;
    impl1.work();
    return 0;
}

在现代C++中,您将 1. 找出所需的所有权语义,然后 2. 使用适当的内存管理工具(如智能指针(表达它们。值得注意的是,您从不手动执行内存管理。这种努力应该封装在一个唯一负责内存管理的类中(请参阅单一责任原则(。

#include <iostream>
#include <memory>
class StateBase {
public:
    StateBase( int val ) : m_stateInfo(val) {}
    virtual ~StateBase() {}
    virtual int getState() = 0;
protected:
    int m_stateInfo;
};
class StateImpl1 : public StateBase {
public:
    StateImpl1() : StateBase( 1 ) {}
    ~StateImpl1() {}
    int getState() {
        //std::cout << "stateimpl:" << m_stateInfo << std::endl;
        return m_stateInfo;
    }
};
class DeviceBase {
public:
    // Constructor says: Give me exclusive ownership of a StateBase.
    DeviceBase(std::unique_ptr<StateBase> pState) : mp_state(std::move(pState)) {}
    // Destructor (implicitly generated) takes care of cleanup.
    virtual void work() = 0;
protected:
    std::unique_ptr<StateBase> mp_state;
};
class DeviceImpl1 : DeviceBase {
public:
    DeviceImpl1() : DeviceBase(std::make_unique<StateImpl1>()) {}
    // Base class constructor handles cleanup.
    void work() {
        std::cout << "DeviceImpl1 work: state = " << mp_state->getState() << std::endl;
    }
};

int main() {
    DeviceImpl1 impl1;
    impl1.work();
    return 0;
}

我们在这里所做的只是澄清DeviceBase拥有StateBase的独特所有权。通过这样做,我们可以消除所有析构函数(std::unique_ptr为我们处理内存管理,另请参阅 RAII(。我更喜欢= default;而不是空的析构函数实现,但这在很大程度上无关紧要。自动生成的 DeviceBase 析构函数将调用unique_ptr析构函数,该析构函数将delete存储的StateBase实例。

请注意,您的原始代码不遵循三/五/零的规则,因此在尝试复制类的实例时会遇到问题(阅读:双释放等(。在上面使用 std::unique_ptr 的代码中,无法复制 DeviceBaseDeviceImpl1 类(因为无法复制std::unique_ptr成员(。

继承公共基类:

#include <iostream>
class StateBase {
public:
    StateBase(int val) : m_stateInfo(val) {}
    virtual ~StateBase() {}
    virtual int getState() = 0;
protected:
    int m_stateInfo;
};
class StateImpl1 : public StateBase {
public:
    StateImpl1() : StateBase(1) {}
    ~StateImpl1() {}
    int getState() {
        //std::cout << "stateimpl:" << m_stateInfo << std::endl;
        return m_stateInfo;
    }
};
class DeviceBase {
public:
    DeviceBase(StateBase* pState) : mp_state(pState) {}
    ~DeviceBase() {} // TODO or delete here? but then it's a bit asymmetric...
    virtual void work() = 0;
protected:
    StateBase* mp_state;
};
class DeviceImpl1 : **public DeviceBase** { // Change is here
public:
    DeviceImpl1() : DeviceBase(new StateImpl1()) {}
    // TODO d'tor here? but then base is left without valid ptr to "mp_state"
    ~DeviceImpl1() { delete mp_state; }
    void work() {
        std::cout << "DeviceImpl1 work: state = " << mp_state->getState() << std::endl;
    }
};

如何初始化 DeviceImpl1 实例 impl1 并调用 delete 来执行这两个析构函数:

int main() {
    DeviceImpl1* impl1 = new DeviceImpl1();
    DeviceBase* base = impl1;
    impl1->work();
    delete base; // This will execute both of the destructor.
    return 0;
}