以静态成员C ++ FAQ的地址为例

时间:2014-06-19 08:43:21

标签: c++

this C ++ FAQ试图传达什么?

  

如果(并且仅当)它具有类外定义,您可以获取静态成员的地址:

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
    // ...
}

然而这compiles !

2 个答案:

答案 0 :(得分:9)

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

它在没有优化的情况下给出了链接器错误。

如果您开始使用p1(例如std::cout << p1 << p2 << std::endl;Link

,您也会收到链接器错误

答案 1 :(得分:5)

常见问题解答中的评论非常具有误导性; AE::c6和{。} AE::c7是左值。如果没有AE::c7的定义, 有问题的代码违反了一个定义规则:

  

表达式可能会被评估,除非它是   未评估的操作数或其子表达式。一个变量   其名称显示为可能评估的表达式   除非它是满足要求的对象,否则使用odr   出现在常量表达式和左值到右值   转换立即应用。 [...]

     

[...]

     

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

实际上,链接器通常会生成错误 if 编译器实际上需要对象的地址。在你的 如果p2以后没有使用过,那么编译器就不需要了 地址,因为优化将删除p1的定义。 发生这种情况的更常见的情况是像 以下内容:

std::vector<int> v;
v.push_back( AE::c6 );

由于std::vector<>::push_back需要参考,因此没有 立即左值到右值转换,定义是 需要。实际上,std::vector<>::push_back是一个模板 函数(通常是内联的),所以编译器可以看到它 实现,并将值传播到函数中 到实际的左值到右值转换的地方 发生,代码将编译和工作。但它仍然存在 正式未定义的行为。