与其他类成员一样的依赖类
我有一个类 B
,需要构造类 A
的实例:
class B
{
B(A* a); // there is no default constructor
};
现在我想创建一个包含 B
作为成员的类,所以我还需要添加 A
作为成员并将其提供给 B
的构造函数:
class C
{
C() : a(), b(&a) {}
A a; // 1. initialized as a()
B b; // 2. initialized as b(&a) - OK
};
但问题是,如果有人偶尔更改变量的顺序定义在类中,它会破坏
class C
{
C() : a(), b(&a) {}
B b; // 1. initialized as b(&a) while "a" uninitialized
A a; // too late...
};
有没有一个好的方法可以解决这个问题而不修改类A
和B
?谢谢。
I have a class B
that requires an instance of class A
to be constructed:
class B
{
B(A* a); // there is no default constructor
};
Now I want to create a class that contains B
as a member, so I also need to add A
as a member and provide it to B
's constructor:
class C
{
C() : a(), b(&a) {}
A a; // 1. initialized as a()
B b; // 2. initialized as b(&a) - OK
};
But the problem is that if someone occasionally changes the order of the variables definition in the class, it will break
class C
{
C() : a(), b(&a) {}
B b; // 1. initialized as b(&a) while "a" uninitialized
A a; // too late...
};
Is there a good way to resolve this without modifying the classes A
and B
? Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
打开编译器警告;对于 gcc,这是 -Wreorder(包含在 -Wall 中):
或者,使用类似 lint 的工具来检测它。
他们为什么要这样做呢?我怀疑您对可能发生的事情过于担心。即便如此,您也可以在课堂上发表评论:
不要低估恰到好处的评论的力量。 :) 然后让那些故意忽视他们的人得到他们应得的;毕竟你使用的是 C++。
Turn on compiler warnings; for gcc, this is -Wreorder (which is included in -Wall):
Alternatively, use a lint-like tool that detects this.
Why would they do this? I suspect you're worrying too much about what might happen. Even so, you can leave a comment in the class:
Don't underestimate the force of well-placed comments. :) Then allow someone who purposefully ignores them to get what they deserve; you are using C++, after all.
使用著名的 C++ 习惯用法 Base-from-Member 来解决这个问题。
将基类定义为,
现在,
a
保证在b
之前初始化。Use the well-known C++ idiom called Base-from-Member to solve this problem.
Define a base class as,
Now,
a
is guaranteed to be initialized beforeb
.将 b 存储在 unique_ptr 中,并将其设置在主体中,而不是初始值设定项列表中:
Store b in a unique_ptr, and set it in the body, not in the initializer list:
一种选择是不显式存储 A,而是使用动态分配来创建一个新的 A 来存储在 B 中:
由于这保证了 A 在 B 之前创建,因此应该可以防止此问题发生。
One option would be to not explicitly store the A, but instead to use dynamic allocation to create a new A to store in the B:
Since this guarantees that the A is created before the B, this should prevent this problem from ever occurring.
问题是你用第三个例子是搬起石头砸自己的脚。在 C++ 中,类/结构中成员变量的顺序很重要。无论您如何解决特定问题,如果由于类设计/成员布局不佳而将未初始化的数据传递给构造函数,您将使用未初始化的数据,并可能获得未定义的行为,具体取决于适当的代码类型。
为了解决您的特定示例,如果
B
确实需要A
并且关系是一对一的,为什么不创建一个新类AB
,它具有按正确的顺序创建A
对象和B
对象,并将A
的地址传递给B
。也就是说:现在类
C
可以通过使用AB
代替A
和B
来避免排序问题:如上所述,这当然假设
A
和B
之间存在 1:1 关系。如果一个A
对象可以被许多B
对象共享,事情就会变得更加复杂。The problem is that you are shooting yourself in the foot with the third example. In C++ the order of member variables in a class/struct matters. No matter how you go about solving your particular problem, if you pass uninitialized data to a constructor due to poor class design / member layout, you will be working with unitialized data and possibly get undefined behavior, depending on the sort of code in place.
To address your particular example, if
B
really requires anA
and the relationship is one to one, why not create a new classAB
that has both anA
object and aB
object in the right order and pass the address ofA
toB
. That is:now class
C
can avoid the ordering problem by usingAB
instead ofA
andB
:As forementioned, this of course assumes a 1:1 relationship between
A
andB
. If anA
object can be shared by manyB
objects, things get more complicated.我不确定您对 C 的实现和结构有多少控制权,但是是否有必要在类 C 中使用对象本身?您能否重新定义类以使用指针,然后将它们从初始化列表中移出,例如,
这可以避免声明中的顺序问题,但会带来确保正确创建它们的新问题。另外,如果您经常创建大量 C 语言,则初始化列表会稍微快一些。
I'm not sure how much control you have over the implementation and structure of C but is it necessary to use the objects themselves in class C? Could you redefine the class to use pointers instead and then move them from the initialization list, e.g.
This avoids the issue of order in the declaration, but gives you the new issue of ensuring they're created correctly. Also, if you create A LOT of C's very often, an initialization list is slightly faster.