好奇段错误与歧视联盟和可选<>
问题描述:
我想知道什么可能导致segfaults在这个简单的例子中使用std :: experimental :: optional和union类型。有趣的是segfault和gcc都出现了segfault,但是出现在两个不同的地方。好奇段错误与歧视联盟和可选<>
我也对从下面的日志中看到的复制和破坏的猥亵量感到困惑,想知道是否有更好的/惯用的方法来避免这么多显然多余的操作?在这种情况下,考虑到这里的所有对象都是按值传递和访问的,它是否有助于切换所有构造函数以获取右值引用并在任何地方使用std :: move?
#include <iostream>
#include <vector>
// https://github.com/akrzemi1/Optional
#include "Optional/optional.hpp"
using std::cout;
using std::vector;
using std::experimental::optional;
struct X {
int y;
X(int y) : y(y) { cout << "X::X(int)\n"; }
X(const X& x) : y(x.y) { cout << "X::X(const X&)\n"; }
~X() noexcept { cout << "X::~X()\n"; }
};
struct A {
vector<X> x;
A(const vector<X>& x) : x(x) { cout << "A::A(const vector<X>&)\n"; }
A(const A& a) : x(a.x) { cout << "A::A(const A&)\n"; }
~A() noexcept { cout << "A::~A()\n"; }
static optional<A> get() {
cout << "A::get()\n";
return A({ X(1), X(2) });
}
};
struct M {
union { A a; };
M(A a) : a(a) {cout << "M::M(A)\n";}
M(const M &m) { a = m.a; }
~M() noexcept {
cout << "M::~M()\n";
(&a)->A::~A();
}
static optional<M> get() {
cout << "M::get()\n";
auto a = A::get();
return M(*a);
}
};
struct P {
vector<M> m;
P(const vector<M>& m) : m(m) { cout << "P::P(const vector<M>&)\n"; }
P(const P& p) : m(p.m) { cout << "P::P(const P&)\n"; }
static optional<P> get() {
cout << "P::get()\n";
auto m1 = M::get();
auto m2 = M::get();
vector<M> m;
cout << "push message 1\n";
m.push_back(*m1);
cout << "push message 2\n";
m.push_back(*m2);
return P(m);
}
};
int main() {
auto p = P::get();
cout << (*p).m[1].a.x[0].y << "\n";
}
GCC失败是这样的:
P::get()
M::get()
A::get()
X::X(int)
X::X(int)
X::X(const X&)
X::X(const X&)
X::X(const X&)
X::X(const X&)
A::A(const vector<X>&)
X::X(const X&)
X::X(const X&)
A::A(const A&)
A::~A()
X::~X()
X::~X()
X::~X()
X::~X()
X::~X()
X::~X()
X::X(const X&)
X::X(const X&)
A::A(const A&)
M::M(A)
X::X(const X&)
X::X(const X&)
A::A(const A&)
'./a.out' terminated by signal SIGBUS (Misaligned address error)
#0 0x0000000100003c59 in X* std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m<X const*, X*>(X const*, X const*, X*)()
#1 0x000000010000364e in X* std::__copy_move_a<false, X const*, X*>(X const*, X const*, X*)()
#2 0x0000000100002f3c in __gnu_cxx::__normal_iterator<X*, std::vector<X, std::allocator<X> > > std::__copy_move_a2<false, __gnu_cxx::__normal_iterator<X const*, std::vector<X, std::allocator<X> > >, __gnu_cxx::__normal_iterator<X*, std::vector<X, std::allocator<X> > > >(__gnu_cxx::__normal_iterator<X const*, std::vector<X, std::allocator<X> > >, __gnu_cxx::__normal_iterator<X const*, std::vector<X, std::allocator<X> > >, __gnu_cxx::__normal_iterator<X*, std::vector<X, std::allocator<X> > >)()
#3 0x00000001000025f8 in __gnu_cxx::__normal_iterator<X*, std::vector<X, std::allocator<X> > > std::copy<__gnu_cxx::__normal_iterator<X const*, std::vector<X, std::allocator<X> > >, __gnu_cxx::__normal_iterator<X*, std::vector<X, std::allocator<X> > > >(__gnu_cxx::__normal_iterator<X const*, std::vector<X, std::allocator<X> > >, __gnu_cxx::__normal_iterator<X const*, std::vector<X, std::allocator<X> > >, __gnu_cxx::__normal_iterator<X*, std::vector<X, std::allocator<X> > >)()
#4 0x0000000100001d19 in std::vector<X, std::allocator<X> >::operator=(std::vector<X, std::allocator<X> > const&)()
#5 0x00000001000012ad in A::operator=(A const&)()
#6 0x00000001000012d7 in M::M(M const&)()
#7 0x0000000100001356 in std::experimental::storage_t<M>::storage_t<M>(M&&)()
#8 0x0000000100001393 in std::experimental::optional_base<M>::optional_base(M&&)()
#9 0x00000001000013c4 in std::experimental::optional<M>::optional(M&&)()
#10 0x0000000100001456 in M::get()()
#11 0x00000001000016a8 in P::get()()
#12 0x0000000100000db1 in main()
而铿锵有时不会崩溃,有时确实像这样:
P::get()
M::get()
A::get()
X::X(int)
X::X(int)
X::X(const X&)
X::X(const X&)
X::X(const X&)
X::X(const X&)
A::A(const vector<X>&)
X::X(const X&)
X::X(const X&)
A::A(const A&)
A::~A()
X::~X()
X::~X()
X::~X()
X::~X()
X::~X()
X::~X()
X::X(const X&)
X::X(const X&)
A::A(const A&)
M::M(A)
X::X(const X&)
X::X(const X&)
A::A(const A&)
X::X(const X&)
X::X(const X&)
M::~M()
A::~A()
X::~X()
X::~X()
A::~A()
X::~X()
X::~X()
A::~A()
X::~X()
X::~X()
M::get()
A::get()
X::X(int)
X::X(int)
X::X(const X&)
X::X(const X&)
X::X(const X&)
X::X(const X&)
A::A(const vector<X>&)
X::X(const X&)
X::X(const X&)
A::A(const A&)
A::~A()
X::~X()
X::~X()
X::~X()
X::~X()
X::~X()
X::~X()
X::X(const X&)
X::X(const X&)
A::A(const A&)
M::M(A)
X::X(const X&)
X::X(const X&)
A::A(const A&)
X::X(const X&)
X::X(const X&)
M::~M()
A::~A()
X::~X()
X::~X()
A::~A()
X::~X()
X::~X()
A::~A()
X::~X()
X::~X()
push message 1
'./a.out' terminated by signal SIGSEGV (Address boundary error)
答
你是不是在M const&
构造函数的情况下构建A
,您只是在未初始化时分配给它。
工会不构建他们的内容。
这与可选无关。
答
问题(如果我没有错)不是由std::experimental::optional
引起的;这是由struct M
中的union { A a; }
引起的,它在M
复制构造函数中使用。
union { A a; }
是一个C++ 11与非平凡(不平凡的构造函数)的联合。所以,如果我没记错的话,构造函数(和析构函数等)将被删除。
我们可以观察到的M
M(const M &m) { a = m.a; }
拷贝构造函数是没有初始化列表;因此联合中的a
元素未初始化。当执行任务
a = m.a;
的a
等号的左边是初始化和(甚至:如果我没看错)程序的行为是不确定的。
解决方案(我希望):
1)A
A() {};
2在初始化列表中拷贝构造函数
M(const M &m) : a() { a = m.a; }
添加一个默认的构造函数)和初始化a
- - 编辑---
更好的解决方案(感谢亮度种族在轨道):inizialize在初始化列表与A
M(const M &m) : a(m.a) { }
给'A'此举构造函数,使用'一(STD ::移动(一))',而不是拷贝构造函数'a(a)'会删除很多这些副本 –
记录'X'的副本和移动构造函数将有助于查看工会是否出现问题 –
@MM是的,谢谢指出,我缩短了所有变量名,所以它更易于阅读。我已更新该帖子。 – aldanor