I was wondering what segfaults might call in this simple example using std :: experimental :: optional and union. Curiously, segfault happens in both clang and gcc, but in two different places.
I am also puzzled by the obscene copying and destruction, as can be seen from the magazines below, I wonder if there is a better / idiomatic way to avoid so many obviously redundant operations? In such cases, given that all objects here are passed and accessible by value, will they help switch all the constructors to get rvalue references and use std :: move everywhere?
#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 ends as follows:
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 ()
whereas clang sometimes does not crash, and sometimes it does this:
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)