【问题标题】:Is it legal to assign heap allocated class object to stack allocated object in C++?在 C++ 中将堆分配的类对象分配给堆栈分配的对象是否合法?
【发布时间】:2020-12-19 09:07:52
【问题描述】:

在 C++ 中,我们可以通过取消引用将类的堆分配对象分配给堆栈分配对象。看起来没有问题,即使析构函数也能正常工作,但这样写代码是好是坏?

#include <iostream>

class cls {
public:
    cls(int n) : pInt{new int{n}} {
        std::cout << "Constructor\n";
    }

    int *pInt;

    ~cls() { 
        std::cout << "Destructor\n";

        delete pInt; 
    }
};

int main() {
    cls *hObj = new cls{100};
    cls sObj = *hObj;
}

【问题讨论】:

  • 这个程序好用吗?令人惊讶(因为 Some 程序员老兄指出的原因)。 你确定你周围没有堆栈转储吗?你检查退出状态了吗?在第二个“析构函数”输出之后有什么有趣的控制台消息吗?
  • 顺便说一句,如果您只是使用向量而不是手动分配(这通常是要做的事情),您可以避免动态内存管理问题。
  • @Peter-ReinstateMonica 没有“第二个”输出,因为只有一个对象被破坏:sObj。 OP 永远不会删除 hObj,因此它的析构函数永远不会运行。
  • @Someprogrammerdude 对,我只是在阅读您帖子下的其他 cmets。当然只有 1 个。事实上,可以像 cls hObj = *(new cls{100}) 一样使用浅拷贝作为 RAII 哨兵,默默地将原始对象送入遗忘!并不是说我会宽恕这种风格......

标签: c++ constructor destructor heap-memory stack-memory


【解决方案1】:

他们复制是可以的,但请注意编译器生成的复制构造函数将执行 shallow 复制。

这意味着,指针是被复制的,而不是它所指向的。这导致您有 two 使用完全相同的 pInt 指针反对,指向完全相同的内存。而你只能delete那段记忆一次

这就是the rules of three, five and zero的原因。


至于为什么这个程序似乎可以工作,那是因为你没有delete hObj。只有sObj 析构函数会运行,因此在当前显示的代码中只有一个delete pInt

如果您在程序终止之前添加delete hObj,那么两个析构函数将delete 相同的内存,并且您将有未定义的行为(并且很可能会崩溃)。

【讨论】:

  • 我用clang对其进行了测试,并且只调用了一次析构函数。 godbolt.org/z/4b3Yh4 ;是“感动”了吗?
  • @LouisGo 不,但是 OP 永远不会破坏 hObj 指向的对象。如果您执行delete hObj,那么您将尝试两次delete 内存。
  • @LuisGo 因为 OPs 代码错过了 delete hObj;。 bug x bug = 看起来很好,但不是
  • @Kanony 此类对象的副本始终为其成员共享相同的分配内存。您只能删除其中一个副本。你能用这样的类写出正确的代码吗?也许是吧。这会是一个超级复杂的混乱吗?当然是的
  • @Kanony 如果 cls 遵循 3/5/0 的规则,那么 cls sObj = *hObj; 绝对没问题。不要把这两个问题混为一谈
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-30
  • 2013-01-25
  • 2017-02-21
  • 2018-09-09
  • 1970-01-01
  • 2018-04-02
相关资源
最近更新 更多