类成员作为另一个的引用:在赋值运算符中崩溃

时间:2012-03-19 23:05:47

标签: c++ reference class-members

我有一个班级Bar,其中有一个成员(Bar::foo)内部的引用:

#include<vector>
#include<algorithm>

struct Foo{
    int x, y;
};

struct Bar{
    Foo foo;
    int &x, &y;
    Bar(): x(foo.x), y(foo.y){}
    // copy constructor and assignment operator
    Bar(const Bar& other): foo(other.foo), x(foo.x), y(foo.y){}
    Bar& operator=(const Bar& other){ foo=other.foo; return *this; }
};

int main(void){
    std::vector<Bar> a, b;
    Bar p; p.x=0; p.y=0;
    a.push_back(p);
    std::copy(a.begin(),a.end(),b.begin());
}

使用g++进行编译(没有任何特殊选项),我在赋值运算符中崩溃了。为什么呢?

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400b29 in Bar::operator= (this=0x0, other=...) at ref2.cpp:14
14      Bar& operator=(const Bar& other){ foo=other.foo; return *this; }
(gdb) bt
#0  0x0000000000400b29 in Bar::operator= (this=0x0, other=...) at ref2.cpp:14
#1  0x00000000004016a0 in std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m<Bar*, Bar*> (
__first=0x405010, __last=0x405030, __result=0x0) at /usr/include/c++/4.6/bits/stl_algobase.h:329
#2  0x000000000040148d in std::__copy_move_a<false, Bar*, Bar*> (__first=0x405010, __last=0x405030, __result=0x0)
at /usr/include/c++/4.6/bits/stl_algobase.h:384
#3  0x0000000000401157 in std::__copy_move_a2<false, __gnu_cxx::__normal_iterator<Bar*, std::vector<Bar, std::allocator<Bar> > >, __gnu_cxx::__normal_iterator<Bar*, std::vector<Bar, std::allocator<Bar> > > > (__first=..., __last=..., 
__result=...) at /usr/include/c++/4.6/bits/stl_algobase.h:422
#4  0x0000000000400cc0 in std::copy<__gnu_cxx::__normal_iterator<Bar*, std::vector<Bar, std::allocator<Bar> > >, __gnu_cxx::__normal_iterator<Bar*, std::vector<Bar, std::allocator<Bar> > > > (__first=..., __last=..., __result=...)
at /usr/include/c++/4.6/bits/stl_algobase.h:454
#5  0x00000000004009f4 in main () at ref2.cpp:21

2 个答案:

答案 0 :(得分:4)

这是合法的吗?

不,因为匿名结构不合法。如果您为其命名,它将调用未定义的行为,除非 foo首先正确初始化(特别是如果您初始化,则无法阅读xy成员data)。

一旦解决了所有问题,这会导致其他问题吗?

首先,拥有任何类型的引用成员都会禁止生成赋值运算符。这对你来说可能重要,也可能不重要。然后,编译器生成的复制构造函数会咬你:它只是盲目地复制所有成员,以foo成员的副本结束,引用成员引用原始<的foo / em>对象。如果这个原始对象的生命周期较短,那么就会发生不好的事情。您可能想要编写复制构造函数,或考虑没有引用成员的替代设计。

答案 1 :(得分:0)

首先初始化您的联盟成员,或者它是IIRC未定义的行为。然后,您也可以初始化对工会成员的引用。