文件范围的原子是否受初始化顺序惨败的影响?

时间:2016-06-12 13:03:23

标签: c++ c++11 static initialization undefined-behavior

考虑以下情况,我们在不同的翻译单元中有两个文件范围的对象,这是通过初始化顺序fiasco的未定义行为的常规设置:

a.hpp

struct thing {
public:
    thing(int value);
    ~thing();

    int value() const;

    static int count();

private:
    int _value;
};

a.cpp

#include "a.hpp"

#include <atomic>

namespace {
    std::atomic<int> things;
}

thing::thing(int value) : _value(value) {
    ++things;
}

thing::~thing() {
    --things;
}

int thing::value() const {
    return _value;
}

int thing::count() {
    return things.load();
}

b.cpp

#include <iostream>

#include "a.hpp"

namespace {
    thing static_thing(42);
}

void foo() {
    std::cout << static_thing.value() << ' ' << thing::count() << '\n';
}

此代码是否受到 a.cpp 中文件作用域原子things b.cpp <中作用域static_thing之间的初始化顺序惨败的影响/ STRONG>?如果没有,为什么不呢?特别是,std :: atomic有什么特别的东西可以删除原本清楚的init命令惨败?是否有一个特定的概念可以命名为使用静态断言强制执行此操作?类似的东西:

static_assert(std::is_trivial<decltype(things)>::value, "file static counter is not trivial");

如果不是std::is_trivial,是否有其他概念和相关类型特征可以更好地对此进行建模?

相反,是否有去初始化惨败?同样的问题,如果是,为什么或为什么不。

2 个答案:

答案 0 :(得分:3)

std::atomic<>是一种标准布局类型,具有普通的默认构造函数和简单的析构函数。因此,它在静态初始化阶段初始化,在动态初始化阶段之前,当全局对象的构造函数被调用时。

换句话说,这里没有发生初始化命令惨败。

由于您没有显式初始化命名空间作用域std::atomic<int>,因此它将被初始化为零。

  

§3.6.2非局部变量的初始化

     

具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量应在任何其他初始化发生之前进行零初始化(8.5)。

     

一起,零初始化和常量初始化称为静态初始化;所有其他初始化是动态初始化。在进行任何动态初始化之前,应执行静态初始化。

答案 1 :(得分:1)

我对C ++“初始化顺序惨败”的理解是它仅适用于需要在运行时调用构造函数的情况。如果代码可以下载到内存位置初始化为固定值,那么该值将被放入“初始化数据”链接器部分(.data),就像每个其他预先初始化的POD(Plain Ol'数据)一样),并没有惨败。

我建议atomic符合这个标准。