4

Мне было интересно, что может быть причиной segfaults в этом простом примере, используя std :: experimental :: optional и union. Любопытно, что segfault происходит как в clang, так и в gcc, но в двух разных местах.Любопытный segfault с разграниченным объединением и необязательным <>

Я также озадачен непристойным копированием и разрушением происходящего, что видно из журналов ниже, интересно, есть ли лучший/идиоматический способ избежать стольких явно избыточных операций? В подобных случаях, учитывая, что все объекты здесь переданы и доступны по значению, помогло бы ему переключить все конструкторы для получения ссылок на rvalue и использовать 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) 
+1

давая 'Ā' конструктор перемещения, и с помощью' а (Std :: двигаться (а)) 'вместо из 'a (a)' будет удалять многие из этих копий –

+0

протоколирование 'X' копирует и перемещает конструкторы, чтобы увидеть, что что-то не так с объединением –

+0

@MM Да, спасибо за указание, ve сократили все имена переменных, чтобы их было легче читать. Я обновил сообщение. – aldanor

ответ

6

Вы не Построив A в случае M const& CTOR , вы просто назначаете его, когда он не инициализирован.

Союзы не создают свое содержание.

Это не имеет никакого отношения к дополнительному.

+0

Таким образом, решение должно заключаться в использовании размещения new как в «M (const M &)», так и в «M (A)»? Как в, 'new (& this-> a) A (m.a)' в конструкторе копирования и 'new (& this-> a) A (a)' в нормальном ctor? – aldanor

+2

@aldanor: Я не эксперт по профсоюзам, но предположительно «M (const M & m): a (m.a) {}'. –

+0

@LightnessRacesinOrbit спасибо! См. Мой комментарий ниже, поскольку - поскольку 'M' является типом объединения, это должно быть сделано в купе конструктора копирования, к сожалению, – aldanor

4

Проблема (если я не ошибаюсь) не вызвана std::experimental::optional; это вызвано union { A a; } в struct M и используется в конструкторе копирования M.

union { A a; } - это объединение C++ 11 с нетривиальным (с нетривиальным конструктором). Поэтому, если я хорошо помню, конструктор (и деструктор и т. Д.) Удаляется.

Мы можем заметить, что конструктор копирования из M

M(const M &m) { a = m.a; } 

без списка инициализаторов; поэтому элемент a в объединении неинициализирован. При выполнении заданий

a = m.a; 

a слева от знака равенства не инициализирован и (даже: если я не ошибаюсь) поведение программы не определено.

Решения (я надеюсь):

1) добавить конструктор по умолчанию в A

A() {}; 

2) и инициализировать a в списке инициализации в конструкторе копирования

M(const M &m) : a() { a = m.a; } 

- - EDIT ---

Лучшее решение (спасибо легковесность Гонки в Orbit): inizialize в списке инициализации с копией конструктора A

M(const M &m) : a(m.a) { } 
+0

Зачем инициализировать только для повторного назначения? Почему не 'M (const M & m): a (m.a) {};'? Кстати, вы пропустили двоеточие. –

+0

@LightnessRacesinOrbit: D'ho! ваше право: более простой 'M (const M & m): a (m.a) {}'; спасибо – max66

+0

Но так как 'M' - это тип объединения, стиль инициализации' a (m.a) 'на самом деле не работает. Если бы существовало другое поле объединения, скажем, 'B b', вам нужно было бы иметь оператор switch в теле конструктора копии, как бы вы это сделали?Что, если, кроме того, 'A' и' B' не имеют конструкторов по умолчанию? – aldanor

 Смежные вопросы

  • Нет связанных вопросов^_^