在头文件中分配新对象

时间:2015-09-24 21:23:33

标签: c++

我在调试空指针问题时在代码库中遇到了这种模式:

#include <iostream>                                   

class Foo {                                           
  public:                                             
    Foo() {                                           
      std::cout << "In Foo constructor." << std::endl;
    };                                                
};                                                    

static const Foo* DEFAULT_FOO(new Foo);               

我想到这可能是一个坏主意,将这个常量初始化移动到cpp文件而不是标题修复了我的问题。

我的问题是,这里到底发生了什么,为什么首先允许这样做?

据我了解,这会在调用main函数之前在堆上分配一个对象,并且该构造函数内部的回溯显示了一堆看起来很可怕的内部东西。更糟糕的是,当有多个编译单元时,每个编译单元都会获得自己的头部副本,因此它自己的版本为DEFAULT_FOO;我看到很多副本&#34; In Foo构造函数&#34;在main输出的任何输出之前的程序输出中。

在我的代码库中,DEFAULT_FOO指针的一个对象副本出现了null,并且将DEFAULT_FOO的初始化移动到cpp文件修复了这个问题。是什么给了什么?

3 个答案:

答案 0 :(得分:1)

你的倒数第二段是现场,并且很清楚为什么这是一个坏主意。

你的最后一段,我不知道。由于指针值本身不是常量,因此可能会被其余代码中的任何内容弄乱。

你错过了一件事 - 物体也被泄露了。虽然这不是什么大问题,因为它只需要在程序关闭时删除,如果需要在析构函数中调用任何重要的东西,它将被跳过(除非有外部代码删除指针,这甚至更麻烦。)

因此,您应该将其包装在智能指针中,或者只是使其成为常规对象而不是动态分配,或者检查单例模式。

答案 1 :(得分:0)

当编译单元#include是一个文件时,它基本上只是将标题中的文本插入到编译单元中。那么在原始版本中,每个编译单元都将包含以下行:

static const Foo* DEFAULT_FOO(new Foo);

因此每个人都会分配/构建一个Foo对象。

将该行移动到cpp文件意味着只有一个编译单元实际创建该对象。

答案 2 :(得分:0)

这是错误的代码。首先,你不应该在头文件中声明静态变量 - 它没有任何意义,因为标头包含在每个cpp文件中!所以你最终得到的是不同DEFAULT_FOO的多个副本! (因为每个cpp文件都将其视为静态,因此它创建了自己的本地符号)。这就是您没有看到任何链接错误的原因。

因此,在头文件中声明变量(使用extern),在cpp文件中定义它们,保持冷静并继续学习。