简体   繁体   English

C++ 为什么在定义的编译和链接之前引用外部实例的程序

[英]C++ Why program with extern instance referenced before defined compiles and links

The problem can be shown on a simple example:这个问题可以用一个简单的例子来说明:

extern A<bool> a;
B b(a);
A<bool> a("a");

In header file:在头文件中:

template<typename T>
class A {
    public:
        A(const char * name) : m_name(name) {}

        const char * name() const {
            return m_name;
        }
        ...
        ...
    private:
        const char * m_name;
};

class B {
    public:
        B(A<bool> & a) {
            printf("%s = %p\n", a.name(), &a);
        }
};

The code actually compiles, links and produce:代码实际编译、链接并生成:

(null) = 0044F604

Demo演示

I wonder if this shouldn't be caught by compiler and fail.我想知道这是否不应该被编译器捕获并失败。

Compiler in question is gcc 9.2.0 (mingw-w64-i686) .有问题的编译器是gcc 9.2.0 (mingw-w64-i686)

  1. There is nothing wrong with passing around and using references to uninitialised objects.传递和使用对未初始化对象的引用并没有错。 The standard explicitly allows this.标准明确允许这样做。
  2. It is the programmer's responsibility to use such a reference in one of the limited ways permitted by the standard.程序员有责任以标准允许的有限方式之一使用这样的引用。 The compiler is not required to complain if usage falls outside of the permitted range.如果使用超出允许范围,编译器不需要抱怨。 Instead, the behaviour of a program that does this is undefined.相反,执行此操作的程序的行为是未定义的。

See basic.life/6 and basic.life/7 for detailed information.有关详细信息,请参阅basic.life/6basic.life/7

In C++, global objects within the same translation unit are initialized in the order they are defined (though the order across TU's is undefined ).在 C++ 中,同一翻译单元中的全局对象按照它们定义的顺序进行初始化(尽管跨 TU 的顺序是undefined )。 See [basic.start.init]/2 :[basic.start.init]/2

... Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. ...在单个翻译单元中定义的具有有序初始化的变量应按照它们在翻译单元中的定义顺序进行初始化。

On the other hand, storage for objects of static storage duration is allocated at program loading time, so each global object has an address from the beginning.在另一方面,静态存储持续时间的对象存储在程序加载时间分配的,所以每一个全局对象从一开始的地址。

In general in C++ it is allowed to reference a not-yet-initialized object, but accessing it is undefined behavior.通常,在 C++ 中,允许引用尚未初始化的对象,但访问它是未定义的行为。 Generally no diagnostic is required for undefined behavior.通常不需要对未定义行为进行诊断。

In your case, B can be constructed with a reference to A , and it can save the passed-in reference to be used later:在您的情况下, B可以使用对A的引用来构造,并且它可以保存传入的引用以供以后使用:

class B {
    A<bool> & a_;
    public:
        B(A<bool> & a) : a_(a) { }

        void run() {
            printf("%s = %p\n", a_.name(), &a_);
        }
};

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

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