当程序进入main函数时,为什么要清除这个std :: vector?

时间:2017-12-07 16:23:48

标签: c++ vector static initialization

我遇到的问题是,当初始化所有静态变量时,我在初始化时将元素推入向量,然后当它进入主函数时,向量重置为0,就像它已经清除一样。在我的例子中,向量处于不同的CPP中,但这也显示了问题:

#include <iostream>
#include <vector>

struct List
{
    static std::vector<int> listVector;
};

struct Foo
{
    Foo() 
    {
        std::cout << List::listVector.size() << '\n';   // Prints 0
        List::listVector.push_back(1);
        std::cout << List::listVector.size() << '\n';   // Prints 1
    }
};
Foo fooObj;

std::vector<int> List::listVector;

int main()
{
    std::cout << List::listVector.size() << '\n';   // Prints 0
    List::listVector.push_back(2);
    std::cout << List::listVector.size() << '\n';   // Prints 1
}

我添加到矢量的第一个元素已丢失。我知道必须小心静态全局变量的初始化顺序,但我无法理解为什么向量被清除。我很想到,当Foo构造函数运行时,它会向向量添加一个元素,但尚未创建向量,因为它是在创建Foo对象后写入的。但是,如果是这种情况,那么当我在构造函数中执行此操作时,我添加的是什么向量,并且它打印出的大小为1?

我有点困惑。

3 个答案:

答案 0 :(得分:3)

  

我很想到,当Foo构造函数运行时,它会向向量添加一个元素,但尚未创建向量,因为它是在创建Foo对象后写入的。

是的,这是完全正确的。 fooObj构造函数只访问构造vector 的内存,但尚未构造它。 (因此程序具有未定义的行为,必须修复)

  

但是,如果是这种情况,那么当我在构造函数中执行此操作时,我添加的是什么向量,并且它打印出的大小为1?

编译器只是将内存解释为有效向量,因为它无法另外知道。这恰好工作,因为全局将被构造的内存最初为零,因为执行环境确保所有静态对象的内存最初为零,这恰好与默认构造状态相同(对于您实现的std::vector)定义。程序无法知道包含全零的内存位置还不是有效的向量。

稍后,向量的构造函数运行,重新初始化内存,进入默认构造状态。

Here是一个示例,显示了您的程序的作用:将包含全零的原始内存解释为向量,并向该幻像向量添加元素(实际上并不存在),然后实际构造一个向量记忆。创建真实矢量后,添加到幻像矢量的任何内容都将丢失。

#include <iostream>
#include <vector>

int main()
{
    // initialize a block of memory to zero:
    alignas(std::vector<int>) char memory[sizeof(std::vector<int>)] = {};
    // use that memory as a vector, even though we haven't created any vector
    // (this is undefined behaviour! there is no vector yet!):
    std::vector<int>& vec = *reinterpret_cast<std::vector<int>*>(memory);
    vec.push_back(1);
    // the non-existent "phantom vector" has size 1:
    std::cout << vec.size() << std::endl;
    // now use "placement new" to construct an empty vector in that memory:
    new (memory) std::vector<int>();
    // the real vector is empty, the element in the phantom vector is lost:
    std::cout << vec.size() << std::endl;    
}

要修复程序,您需要在任何引用它之前初始化向量(具体地说,在fooObj构造函数尝试使用之前,通过在fooObj之前定义它)。

答案 1 :(得分:1)

如果您将代码更改为

#include <iostream>
#include <vector>

namespace List
{
    static std::vector<int> listVector;
}

struct Foo
{
    Foo()
    {
        std::cout << List::listVector.size() << '\n';   // Prints 0
        List::listVector.push_back(1);
        std::cout << List::listVector.size() << '\n';   // Prints 1
    }
};
Foo fooObj;

//std::vector<int> List::listVector;

int main()
{
    std::cout << List::listVector.size() << '\n';   // Prints 0
    List::listVector.push_back(2);
    std::cout << List::listVector.size() << '\n';   // Prints 1
}

它应该有用。我不是全局变量(我不使用它们)但我认为struct param不会使它成为真正的全局变量的问题。也许其他用户可以解释一下......

编辑:您还可以删除命名空间,我这样做就可以让List ::

Edit2:如果你想使用struct而不是

struct List
{
    std::vector<int> listVector;
};

static List GlobL;

而不是使用GlobL.listVector,而不是struct obj ist static而不是struct的参数。

答案 2 :(得分:-3)

您必须了解您的程序不会从上到下运行。每个程序都将从main()函数开始。如果main()函数没有被调用,那么main()上面的所有代码基本上都会被忽略。

不应该在这里问这些问题。看起来你是一个初学者,你应该在提问之前先阅读自己的主题。