【问题标题】:Can you stop unused static objects from being constructed?你能阻止构造未使用的静态对象吗?
【发布时间】:2020-06-02 20:23:13
【问题描述】:

当我链接一个包含静态对象的文件时,该对象的构造函数都会运行,而不管该对象是否曾经被使用过,或者是否包含头文件。 g++ 中有没有办法阻止这种行为的发生,或者是不链接文件的唯一答案?

foo.h

#include <iostream>

class Bar {
public:
    Bar(int inMemberInt) {
        std::cout << "In Bar constructor." << std::endl;
    }
};

class Foo {
public:
    static const Bar constVar;
};

foo.cpp

#include "foo.h"

const Bar Foo::constVar(1);

main.cpp

#include <iostream>

int main() {
    std::cout << "Hello." << std::endl; 

    return 1;
}

构建命令

g++ foo.h foo.cpp main.cpp -o main

输出

In Bar constructor.
Hello.

【问题讨论】:

  • 你问的是延迟初始化吗?
  • 我不确定标准是否允许,但如果是,则必须保证没有副作用。由于您打印,这将是一个副作用,因此无法删除。
  • constVar 必须是静态 data 成员吗?如果没有,那么像 Meyer 的单例可能会给你你想要的行为。

标签: c++ build static linker g++


【解决方案1】:

您可以将类设为模板(可能带有默认模板参数),然后静态数据成员的定义仅在程序中某处(odr-)使用时才会被实例化。

不过,这需要您将类成员的定义移动到标题中。如果这影响太大,您可能需要考虑将静态成员放在作为类模板的基类中,只要您不引用任何地方的静态成员。在任何情况下,静态成员的定义都需要移动到标题中(显式实例化会与预期效果相反。)

这并不意味着,如果静态成员 (odr-) 被使用,则初始化程序将仅在程序运行中第一次使用该变量时运行。是否是这种情况是实现定义的。


当变量没有在程序代码中使用时,保证初始化程序永远不会运行,而且保证它在第一次使用时准确运行的替代方法是使用本地@987654321 static 成员函数中的 @ 变量:

static const Bar& constVar() {
    static const Bar instance(1);
    return instance;
};

然后将其用作constVar() 而不是constVar。 (函数的定义也可以是类外的。)然而,这确实会带来性能损失,因为局部静态的实现必须是线程安全的。

【讨论】:

  • 小心静态本地成员 - 便利的代价是每次调用都需要额外的标志和 mutex 锁定/解锁(根据 C++ 标准要求静态本地初始化必须是线程安全的)。
  • @rustyx 我已添加评论。
  • @rustyx gcc 使用原子保护,不涉及互斥锁。
【解决方案2】:

另一种选择是在自己的源文件中定义静态对象。然后将该源文件编译为目标文件,并将其与其他目标文件(如果有)一起链接到静态库 (.a)。将可执行文件(或共享库)链接到静态库时,链接器仅包含静态库中解析任何未解析符号的 .o 文件。因此,如果没有引用该静态对象,则定义它的对象文件不会链接到您的可执行文件或共享库中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-21
    • 1970-01-01
    • 2017-12-02
    • 1970-01-01
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    相关资源
    最近更新 更多