2016-05-14 172 views
4

我想知道什麼可能導致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) 
+1

給'A'此舉構造函數,使用'一(STD ::移動(一))',而不是拷貝構造函數'a(a)'會刪除很多這些副本 –

+0

記錄'X'的副本和移動構造函數將有助於查看工會是否出現問題 –

+0

@MM是的,謝謝指出,我縮短了所有變量名,所以它更易於閱讀。我已更新該帖子。 – aldanor

回答

6

你是不是在M const&構造函數的情況下構建A ,您只是在未初始化時分配給它。

工會不構建他們的內容。

這與可選無關。

+0

所以解決方法是在'M(const M&)'和'M(A)'中都使用放置new?如在中,複製構造函數中的new(&this-> a)A(m.a)'和正常ctor中的new(&this-> a)A(a)'? – aldanor

+2

@aldanor:我不是工會專家,但可能是'M(const M&m):a(m.a){}'。 –

+0

@LightnessRacesinOrbit謝謝!儘管看到我的評論 - 因爲'M'是一個聯合類型,這不得不在複製構造函數體中完成 – aldanor

4

問題(如果我沒有錯)不是由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) { } 
+0

爲什麼初始化只能重新分配?爲什麼不'M(const M&m):a(m.a){};'?順便說一句,你錯過了一個冒號。 –

+0

@LightnessRacesinOrbit:D'ho!你的權利:簡單'M(const M&m):a(m.a){}';謝謝 – max66

+0

但是因爲'M'是一個聯合類型,所以'(m.a)'初始化風格不會真的起作用。如果還有另一個工會領域,比如'B b',那麼你必須在複製構造函數體中有一個switch語句,你會怎麼做?如果'A'和'B'沒有默認的構造函數呢? – aldanor