如果我从不使用静态const变量的地址,那么在使用合理的现代编译器时是否为它分配了内存?
答案 0 :(得分:10)
它取决于变量的类型,以及“常量”是否也意味着“常量表达式”。例如:
static const Foo = get_foo(std::cin);
static const int q = argc * 3;
static const std::string s(gets());
这些变量是常量,但显然需要实际分配。
另一方面,以下常量表达式可能永远不会有物理存储:
static const int N = 1000;
static const std::shared_ptr<void> vp(); // constexpr constructor!
最重要的是,如果您小心,静态constexpr 成员变量不需要定义:
struct Bar
{
int size() const { return N; }
static const int N = 8;
};
// does NOT need "const int Bar::N;"
答案 1 :(得分:3)
有可能不是,但这无关紧要。您不能仅依靠标准来依赖实施细节。
答案 2 :(得分:1)
实际上,静态存储空间可以作为初始二进制加载的一部分,也可以在启动时由运行时分配;但总会在遇到用户代码之前发生。
除了 Kerrek SB 提到的约束之外,如果值本身从未在运行时使用,则可以消除const expr
值的存储。
这并不一定意味着不需要评估值 - 如果静态const expr
仅用作分支条件,则可以静态评估该条件,并且可能不生成其他代码路径或者可能被优化者排除在外。
如果实现可以保证行为就像存储存在一样 - 即可以在编译时评估的比较表达式 - 就像一个不同的static
那么,几乎任何具有const expr
持续时间的存储都可以被消除。 ,指针比较,其中已知rhs是不同变量的别名,或者可能是不兼容的类型。如果只将值读入永远不会读取的变量,也可以将其删除;或者值可以减少到const expr
。
struct Foo{};
static Foo bar; // static instance
Foo* func() {
if ( ! (&bar) ) { // always non-NULL
// this block may be eliminated
Foo* myCopy(new Foo(bar));
return myCopy;
}
// so 'bar' is never referred to, and we know it has no side-
// effects, so the static variable can be eliminated
return new Foo();
}
3.7.1静态存储时间
2.
如果静态存储持续时间的对象具有初始化或具有副作用的析构函数,则即使它看起来未被使用也不应被删除,除非可以按指定的方式删除类对象或其副本在12.8。
答案 3 :(得分:1)
全局变量的内存由链接器保留,而不是编译器。所以问题是链接器是否足够智能,不能为仅由值使用的全局变量保留空间。
这取决于此类数据的类型和用途;例如,浮点常数通常必须从内存中加载,因此即使您不直接使用该地址,它们也必须具有存储空间。
话虽如此,该标准确实指明您能否优化静态存储(3.7.1.2:[basic.stc.static]):
如果具有静态存储持续时间的变量具有初始化或a 具有副作用的破坏者,即使它也不会被消除 似乎未使用,除了类对象或其复制/移动可能 按照12.8的规定予以淘汰。
因此,如果静态const变量具有构造函数或析构函数,则无法对其进行优化(尽管某些编译器/链接器仍会执行此操作)。如果它没有,它可以。它是否取决于链接器。