【问题标题】:Problem with initialize static std::vector<class> in same class constructor在同一类构造函数中初始化静态 std::vector<class> 的问题
【发布时间】:2011-05-28 06:37:07
【问题描述】:

如何在类中更正声明静态向量? 目前我在一行上崩溃了,因为向量初始化太晚了。

样品一

#include "stdafx.h"
#include <vector>    
class A{
private:
    int aValue;
public:
    static std::vector<A*> listOfA;

    A(int i)
    {
        aValue = i;
        A::listOfA.push_back(this); // !!! HERE crash in release mode only, in debug mode items add to vector, but remove when vector initialize
    }
};

A testA(1);
std::vector<A*> A::listOfA;



int _tmain(int argc, _TCHAR* argv[])
{
    return 0;
}

示例二

classA.h

#include <vector>

class A{
private:
    int aValue;
public:
    static std::vector<A*> listOfA;

    A(int i);
};

classA.cpp

#include "stdafx.h"
#include "classA.h"

std::vector<A*> A::listOfA;

A::A(int i)
{
  aValue = i;
  A::listOfA.push_back(this); // !!! HERE crash in release mode only, in debug mode items add to vector, but remove when vector initialize
}

main.cpp

#include "stdafx.h"
#include "classA.h"

A testA(1);

int _tmain(int argc, _TCHAR* argv[])
{
    return 0;
}

在示例 2 中,如果项目中的 cpp 文件具有此顺序(编译顺序),则一切正常: 类A.cpp main.cpp

如果订购这个,我们就会崩溃: 主文件 类A.cpp

【问题讨论】:

  • 我建议阅读更多关于“静态初始化订单惨败”的内容

标签: class visual-c++ vector crash initialization


【解决方案1】:

静态是按照它们在文件中出现的顺序初始化的,所以当你说:

A testA(1);
std::vector<A*> A::listOfA;

第一个静态变量已初始化,但它的构造函数尝试使用第二个静态变量,结果未定义。

如果静态在不同的文件中,初始化的顺序是未指定的,所以如果你幸运或不幸,它可能会起作用)。一般来说,不要编写依赖于静态初始化顺序的代码。

【讨论】:

  • 如何修改类以便在不同文件中进行良好的初始化?
  • 别修改,干脆别做。但是,如果您交换初始化顺序,您的第一个示例将起作用。
  • 在实际代码中它是不同的文件,一个文件使用类,另一个文件使用类
【解决方案2】:

引自:http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14 这个问题有很多解决方案,但一个非常简单且完全可移植的解决方案是用一个全局函数 listOfA() 替换全局对象 listOfA,它通过引用返回对象。

std::vector<A*>& listOfA()
{
    static std::vector<A*> ans;
    return ans;
}

由于静态局部对象是在第一次控制流过它们的声明时构造的,所以上面的新 listOfA() 语句只会发生一次:第一次调用 listOfA()。随后的每个调用都将返回相同的对象。然后你所做的就是将你对 listOfA 的用法更改为 listOfA():

int _tmain(int argc, _TCHAR* argv[])
{
    // do stuff
    A::listOfA().dostuff();
    // do stuff
}

这被称为第一次使用时构造成语,因为它就是这样做的:全局 Fred 对象是在第一次使用时构造的。

这种方法的缺点是对象永远不会被破坏。还有另一种技术可以解决这个问题,但需要小心使用,因为它可能会产生另一个(同样令人讨厌的)问题。

[编辑] 抱歉 nbt,没有看到您已经链接到常见问题解答。他值得称赞[/Edit]

【讨论】:

  • 您可以在全局函数 中创建(在堆栈而不是堆上)本地静态对象并返回它。破坏问题将由标准静态对象破坏处理。这称为延迟初始化:P
  • 回头看,是的。我过度思考了这个问题并回答了一个不同的问题。我发布的内容用于保证多个静态变量的静态初始化顺序,而普通的静态变量可以正常工作。正在编辑我的答案...
猜你喜欢
  • 2020-05-05
  • 1970-01-01
  • 2015-08-05
  • 2020-10-28
  • 1970-01-01
  • 2016-05-03
  • 2015-04-30
  • 2016-02-16
  • 2011-02-15
相关资源
最近更新 更多