带有区别联合和可选<>的好奇段错误

ald*_*nor 4 c++ constructor copy-constructor segmentation-fault c++11

我想知道在这个简单的例子中使用std :: experimental :: optional和union类型可能导致段错误的原因.令人好奇的是,clang和gcc都发生了段错误,但在两个不同的地方.

我也对从下面的日志中看到的大量复制和破坏行为感到困惑,想知道是否有更好/惯用的方法来避免这么多显然多余的操作?在这种情况下,假设这里的所有对象都是按值传递和访问的,那么将所有构造函数切换为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";
}
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会失败了:

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 ()
Run Code Online (Sandbox Code Playgroud)

而clang有时不会崩溃,有时会这样:

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)
Run Code Online (Sandbox Code Playgroud)

Yak*_*ont 6

你是不是构建AM const&构造函数的情况下,你只是分配给它时,它是未初始化.

工会不构建其内容.

这与可选项无关.

  • @aldanor:我不是工会专家,但可能是"M(const M&m):a(ma){}`. (2认同)