我遇到了一个简单的C ++类的奇怪行为。

classA.h

class A
{
public:
  A();
  ~A();
  static const std::string CONST_STR;
};

classA.cpp

#include "classA.h"
#include <cassert>

const std::string A::CONST_STR("some text");

A::A()
{
  assert(!CONST_STR.empty()); //OK
}

A::~A()
{
  assert(!CONST_STR.empty()); //fails
}

的main.cpp

#include <memory>  
#include <classA.h>  

std::auto_ptr<A> g_aStuff; 

int main() 
{ 
  //do something ... 
  g_aStuff = std::auto_ptr<A>(new A()); 
  //do something ... 
  return 0; 
}

我希望访问违规或类似的东西,但我永远不会期望静态const字符串的内容可能会改变。这里有没有人能够很好地解释该代码中会发生什么?

感谢, 诺贝特

有帮助吗?

解决方案

  

我希望访问违规或   类似的东西,但我永远不会想到   那个静态const的内容   字符串可能会改变。

未定义的行为:未定义。如果CONST_STR已被销毁,那么如果您访问它,则无法保证硬件异常。它可能会崩溃,但是它的地址可能会最终包含看起来像空字符串的数据:它的析构函数可能会清除指针或其他内容。

在这种情况下,您说A实例也存储在全局智能指针中,该指针在main()中指定。所以CONST_STR是在A构造函数中访问时构造的,但很可能在智能指针被销毁之前被销毁。我们需要整个计划肯定地说。

[编辑:你做到了。由于CONST_STR和g_aStuff是在不同的编译单元中定义的,因此它们的相对构造顺序不是由标准定义的。我猜测CONST_STR首先被销毁。]

其他提示

编辑:显然缺少的 A :: 是代码原始帖子中的拼写错误。

原始答案:

你的意思是


    const std::string A::CONST_STR("some text");

这样CONST_STR就是类 A

的一部分

否则,您将单独声明它并且初始化 A 的静态成员。

您在两个不同的编译单元中创建了2个静态变量。无法判断它们的初始化顺序。但是他们的析构函数总是以相反的顺序调用。

在您的情况下,似乎发生了下一个场景:

g_aStuff constructor 
CONST_STR constructor

main funciton initializes g_aStuff

CONST_str destructor 
g_aStuff descrutor  

此时CONST_STR.empty()的结果未定义。这可能会触发断言。

classA.cpp中定义的

const std::string CONST_STR("some text");
不是A的成员。该定义如下所示:

const std::string A::CONST_STR("some text");

标准未指定不同翻译单元中全局/静态对象的初始化顺序。但是,它确保在执行该翻译单元的任何功能之前初始化每个这样的对象。

在你的情况下,在 g_aStuff 之后初始化 CONST_STR ,并且由于破坏的顺序与构造顺序相反,它在它之前被销毁。因此,从 A 的析构函数访问 CONST_STR 会调用未定义的行为 - 您可能会遇到访问冲突,或者可能没有。

然而, CONST_STR 在执行 A 的构造函数之前被初始化,因为它们位于相同的翻译单元中。

如果存在A的全局实例(或类型A的静态类成员),则可能会发生这种情况。由于没有定义全局变量和静态的初始化顺序(交叉翻译单位),它可以是。

查看完整代码,您将依赖于编译单元(classA.cpp和main.cpp)的销毁顺序。如果你在main中创建g_aStuff作为本地,你的断言应该通过。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top