初始化相互引用的对象 [英] Initializing mutually-referencing objects

查看:92
本文介绍了初始化相互引用的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下一对相互引用的类型:

  struct A; 
struct B {A&一个; };
struct A {B& b; };

这可以使用GCC,Clang,Intel,MSVC中的聚合初始化来初始化,而不是SunPro需要用户定义的ctors。

  struct {A first; B second;} pair = {pair.second,pair.first}; 

此初始化是否合法?



稍微更复杂的演示: http://ideone.com/P4XFw



现在,注意太阳的警告,用用户定义的构造函数的类怎么样?下面的工作在GCC,clang,Intel,SunPro和MSVC,但它是合法的吗?

  struct A; 
struct B {A& ref; B(A& a):ref(a){}};
struct A {B& ref; A(B& b):ref(b){}};

struct {B first; A second;} pair = {pair.second,pair.first};

演示: http: /ideone.com/QQEpA



最后,如果容器不是微不足道的,例如(在G ++,Intel,Clang(有警告),但不是MSVC(pair在初始化器中未知)或SunPro(pair不是一个结构)工作

  std :: pair< A,B> pair(pair.second,pair.first); 

$ b b

从我可以看到,§3.8[basic.life] / 6 在生命周期开始之前禁止访问非静态数据成员,但是如果是,那么所有三个初始化都是非法的?§8.3.2[dcl.ref] / 5 引用应该被初始化为引用一个有效的对象,这可能使所有三个非法,但也许我错过了一些东西,编译器接受这个原因。



PS:我意识到这些类在任何方面都不实用,因此语言 - 律师标签。相关和稍微更实用的老讨论在这里:无指针的C ++中的循环引用

解决方案

从编译器的角度来看,引用只不过是const指针。用指针重写你的例子,它变得清楚如何和为什么它的工作原理:

  struct A; 
struct B {A * a; };
struct A {B * b; };
struct {A first; B second;} pair = {&(pair.second),&(pair.first)}; //圆括号为清楚

Schollii写道:内存被预先分配,因此可寻址。由于引用/指针,因此没有访问或评估。这只是取地址的第二和第一,简单的指针算术。



我可以couldt如何使用引用在除操作符之外的任何地方是语言滥用,但我认为这个例子很好地突出了这个问题:)



(从现在开始我手动编写所有的ctors你的编译器可能或可能不请为此自动执行此操作。)
尝试使用新的:

  struct A; 
struct B {A&一个; B(A& arg):a(arg){;}};
struct A {B& b; A(B& arg):b(arg){;}};
typedef struct PAIR {A first; B秒; PAIR(B& argB,A& argA):first(argB),second(argA){;}} * PPAIR,* const CPPAIR;
PPAIR pPair = NULL; //刚刚清除垃圾或0xCDCD
pPair = new PAIR(pPair-> second,pPair-> first);

现在它取决于执行顺序。如果最后一次分配(在ctor之后),second.p将指向0x0000,first.ref指向例如。 0x0004。

其实, http://codepad.org/yp911ug6 这里的ctors最后运行(最有意义的),因此一切正常(即使它似乎不应该)。



不能谈论模板。 p>

但你的问题是这是合法吗?没有法律禁止。

它会工作吗?嗯,我不相信编译器生成器足够对此做任何说明。


Consider the following pair of mutually referencing types:

struct A;
struct B { A& a; };
struct A { B& b; };

This can be initialized with aggregate initialization in GCC, Clang, Intel, MSVC, but not SunPro which insists that user-defined ctors are required.

struct {A first; B second;} pair = {pair.second, pair.first};

Is this initialization legal?

slightly more elaborate demo: http://ideone.com/P4XFw

Now, heeding Sun's warning, what about classes with user-defined constructors? The following works in GCC, clang, Intel, SunPro, and MSVC, but is it legal?

struct A;
struct B { A& ref; B(A& a) : ref(a) {} };
struct A { B& ref; A(B& b) : ref(b) {} };

struct {B first; A second;} pair = {pair.second, pair.first};

demo: http://ideone.com/QQEpA

And finally, what if the container is not trivial either, e.g. (works in G++, Intel, Clang (with warnings), but not MSVC ("pair" unknown in initializer) or SunPro ("pair is not a structure")

std::pair<A, B> pair(pair.second, pair.first);

From what I can see, §3.8[basic.life]/6 forbids access to a non-static data member before lifetime begins, but is lvalue evaluation of pair.second "access" to second? If it is, then are all three initializations illegal? Also, §8.3.2[dcl.ref]/5 says "reference shall be initialized to refer to a valid object" which probably makes all three illegal as well, but perhaps I'm missing something and the compilers accept this for a reason.

PS: I realize these classes are not practical in any way, hence the language-lawyer tag. Related and marginally more practical old discussion here: Circular reference in C++ without pointers

解决方案

From compiler point of view references are nothing else but const pointers. Rewrite your example with pointers and it becomes clear how and why it works:

struct A;
struct B { A* a; };
struct A { B* b; };
struct {A first; B second;} pair = {&(pair.second), &(pair.first)}; //parentheses for clarity

As Schollii wrote: memory is allocated beforehand, thus addressable. There is no access nor evaluation because of references/pointers. That's merely taking addresses of "second" and "first", simple pointer arithmetics.

I could rant about how using references in any place other than operator is language abuse, but I think this example highlights the issue well enough :)

(From now on I write all the ctors manually. Your compiler may or may not do this automagically for you.) Try using new:

struct A;
struct B { A& a; B(A& arg):a(arg){;} };
struct A { B& b; A(B& arg):b(arg){;} };
typedef struct PAIR{A first; B second; PAIR(B& argB, A& argA):first(argB),second(argA){;}} *PPAIR, *const CPPAIR;
PPAIR pPair = NULL;// just to clean garbage or 0xCDCD
pPair = new PAIR(pPair->second, pPair->first);

Now it depends on order of execution. If assignment is made last (after ctor) the second.p will point to 0x0000 and first.ref to e.g. 0x0004.
Actually, http://codepad.org/yp911ug6 here it's the ctors which are run last (makes most sense!), therefore everything works (even though it appears it shouldn't).

Can't speak about templates, though.

But your question was "Is that legal?". No law forbids it.
Will it work? Well, I don't trust compiler makers enough to make any statements about that.

这篇关于初始化相互引用的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆