【问题标题】:How come the definition order is not followed when defining static member variables?定义静态成员变量时怎么不遵循定义顺序?
【发布时间】:2017-07-01 14:02:42
【问题描述】:

我知道不同翻译单元的静态变量的初始化顺序问题。但是,我的问题是在一个翻译单元内,实际上是在一个结构内:

template <int size>
struct SlidingTile {
    using AllActions = std::array<int, size>;
    using AllMDDeltas = std::array<int, size>;

    int mdDelta(int i) const {
        return mdDeltas_[i];
    }

    static AllActions computeAllActions() {
        std::cout << "computeAllActions" << std::endl;
        AllActions res;
        for (int i = 0; i < size; ++i) res[i] = i;
        return res;
    }

    static AllMDDeltas computeAllMDDeltas() {
        std::cout << "Entered computeAllMDDeltas" << std::endl;
        AllActions res;
        for (int i = 0; i < size; ++i) res[i] = 10 * allActions_[i];
        std::cout << "Exiting computeAllMDDeltas" << std::endl;
        return res;
    }

private:
    static const AllActions allActions_;
    static const AllMDDeltas mdDeltas_;
};

template <int size>
const typename SlidingTile<size>::AllActions
    SlidingTile<size>::allActions_ = SlidingTile<size>::computeAllActions();

template <int size>
const typename SlidingTile<size>::AllMDDeltas
    SlidingTile<size>::mdDeltas_ = SlidingTile<size>::computeAllMDDeltas();

int main() {
    SlidingTile<3> s;
    std::cout << s.mdDelta(2) << std::endl;
    return 0;
}

输出是:

Entered computeAllMDDeltas
Exiting computeAllMDDeltas
computeAllActions

令我惊讶的是,computeAllMDDeltascomputeAllActions 之前被调用,因此allActions_computeAllMDDeltas 中使用时不会被初始化。有趣的是,即使在computeAllMDDeltas 中使用了allActions_,也不会调用computeAllActions

为什么会发生这种情况,在这种情况下建议的方法是什么?

【问题讨论】:

  • computerAllMDDeltas 使用 allActions_ 的位显然不是无关紧要的 - 但您仍然删除了它。请给我们minimal reproducible example - 这对你来说有点麻烦,但由于你是有问题的人,这似乎是合理的。
  • 确定 computeAllMDDeltas正在使用allActions_吗?您能否更新代码以提供有关用法的一些想法。
  • 请注意allActions_mdDeltas_ 的定义是模板 的定义,而不是对象的定义。 SlidingTile&lt;2, 3&gt;::allActions_SlidingTile&lt;2, 3&gt;::mdDeltas_ 没有明确的定义。
  • 我更改了程序以获得进一步简化的完整示例。
  • @AlwaysLearning:像往常一样,实例化模板生成的实体没有具体的定义点。您对静态成员的模板定义还不是“真正的”定义。它们只是模板。它们将在实例化期间“实现”。没有人知道他们将在哪里肉化以及以什么顺序。

标签: c++ initialization static-variables


【解决方案1】:

定义静态成员变量时怎么不按照定义顺序?

因为标准说初始化是无序的:

[basic.start.init] /2(N4140标准草案)

... 明确专门化的类模板静态数据成员的定义已排序初始化。其他 类模板静态数据成员(即隐式或显式实例化的特化)具有无序 初始化。 ...


在这种情况下建议的方法是什么?

与跨翻译单元的初始化相同:第一次使用时构造成语:

struct SlidingTile {
    // ...
private:
    static const AllActions& allActions() {
        static const AllActions instance = computeAllActions();
        return instance;
    }
    static const AllMDDeltas& mdDeltas() {
        static const AllMDDeltas instance = computeAllMDDeltas();
        return instance;
    }
};

【讨论】:

  • 我是否正确地认为,一旦对这些函数的调用被内联,使用这种技术就会产生零开销?
  • @AlwaysLearning 如果程序是用多线程支持编译的,那么会有一点开销。初始化必须同步,以防止在多个线程同时调用该函数时可能发生的竞争条件。
  • 另外,您的意思是使用static const(即static 是否被错误地省略了?)来防止每次调用相应函数时重新计算这些变量?
  • @AlwaysLearning 哎呀!的确,我是故意的。返回对非静态本地的引用是非常错误的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多