获取静态成员的地址



这个 c++常见问题解答试图传达什么?

可以取静态成员的地址,当(仅当)它具有类外定义:

class AE {
    // ...
public:
    static const int c6 = 7;
    static const int c7 = 31;
};
const int AE::c7;   // definition
int f()
{
    const int* p1 = &AE::c6;    // error: c6 not an lvalue
    const int* p2 = &AE::c7;    // ok
    // ...
}

但是这个可以编译!

您使用-O2进行编译。编译器可以优化掉const int* p1 = &AE::c6;赋值(因为它没有效果),因此它不需要在最终代码中使用AE::c6的地址,这就是它编译的原因。

它给出一个没有优化的链接错误。

你也得到一个链接错误,如果你开始使用p1(例如std::cout << p1 << p2 << std::endl;)链接

FAQ中的评论很容易误导人;AE::c6AE::c7为左值。如果没有AE::c7的定义,有问题的代码违反了一个定义规则:

表达式可能被求值,除非它是未求值的操作数或其子表达式。一个变量谁的名字显示为可能求值的表达式是除非它是满足要求的对象,否则不使用用于出现在常量表达式和左值到右值之间立即应用转换。[…)

[…]

每个程序都应该包含每个函数的一个定义非内联函数或变量,在其中不使用程序;不需要诊断。

在实践中,如果链接器通常会生成一个错误编译器实际上需要对象的地址。在你的情况下,如果以后不使用p2,则编译器将不需要因为优化将删除p1的定义。更常见的情况是:
std::vector<int> v;
v.push_back( AE::c6 );

由于std::vector<>::push_back接受引用,所以没有立即左值到右值的转换,定义是必需的。实际上,std::vector<>::push_back是一个模板函数(通常是内联的),这样编译器就可以看到它的实现,并将值向下传播到函数中到左值到右值转换的地方发生,则代码将编译并正常工作。但它仍然是正式未定义行为

最新更新