简体   繁体   English

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

[英]Taking address of a static member C++ FAQ

What does this C++ FAQ try to convey ? 这个 C ++ FAQ试图传达什么?

You can take the address of a static member if (and only if) it has an out-of-class definition : 如果(并且仅当)它具有类外定义,您可以获取静态成员的地址:

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

However this compiles ! 然而这编译!

You use -O2 to compile. 您使用-O2进行编译。 The compiler can optimize away the const int* p1 = &AE::c6; 编译器可以优化const int* p1 = &AE::c6; assignment (as it has no effect) and therefore it does not need the address of AE::c6 in the final code, that's why it compiles. 赋值(因为它没有效果)因此它在最终代码中不需要AE::c6的地址,这就是它编译的原因。

It gives a linker error without optimization. 它在没有优化的情况下提供链接器错

You also get a linker error if you start to use p1 (eg std::cout << p1 << p2 << std::endl; ) Link 如果开始使用p1也会出现链接器错误(例如std::cout << p1 << p2 << std::endl;链接

The comment in the FAQ is very misleading; 常见问题解答中的评论非常误导; both AE::c6 and AE::c7 are lvalues. AE::c6AE::c7都是左值。 If there is no definition of AE::c7 , the code in question violates the one definition rule: 如果没有AE::c7定义,则相关代码违反了一个定义规则:

An expression is potentially evaluated unless it is an unevaluated operand or a subexpression thereof. 除非它是未评估的操作数或其子表达式,否则可能会评估表达式。 A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression and the lvalue-to-rvalue conversion is immediately applied. 名称显示为潜在评估表达式的变量是odr-used,除非它是满足出现在常量表达式中的要求的对象,并且立即应用左值到右值转换。 [...] [...]

[...] [...]

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; 每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义; no diagnostic required. 无需诊断。

In practice, the linker will generally generate an error if the compiler actually needed the address of the object. 实际上, 如果编译器实际需要对象的地址,链接器通常会生成错误。 In your case, if p2 isn't used later, then the compiler won't need the address, since optimization will remove the definition of p1 . 在您的情况下,如果稍​​后不使用p2 ,则编译器将不需要该地址,因为优化将删除p1的定义。 An even more frequent case where this occurs are things like the following: 发生这种情况的更常见的情况如下:

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

Since std::vector<>::push_back takes a reference, there is no immediate lvalue-to-rvalue conversion, and a definition is required. 由于std::vector<>::push_back采用引用,因此没有立即的左值到右值转换,并且需要定义。 In practice, std::vector<>::push_back is a template function (usually inline), so the compiler can see into its implementation, and propagate the value down into the function to the place where the lvalue-to-rvalue conversion actually occurs, and the code will compile and work. 实际上, std::vector<>::push_back是一个模板函数(通常是内联的),因此编译器可以看到它的实现,并将值传播到函数中,实际上是lvalue-to-rvalue转换的地方发生,代码将编译和工作。 But it is still formally undefined behavior. 但它仍然是正式未定义的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM