определение деструктора в классе, производном от типа только для перемещения, дает ошибку времени компиляции при создании с помощью emplace_back или push_back из std :: vector - PullRequest
6 голосов
/ 10 октября 2019

Удаление комментария из следующего кода приводит к ошибке времени компиляции. Похоже, что определение деструктора в производном классе вызывает конструктор копирования в emplace_back

#include <vector>

struct A
{
    A() = default;
    A( A& ) = delete;
    A& operator=( A& ) = delete;
    A( A&& ) = default;
    A& operator=( A&& ) = default;
    ~A(){};
};

struct B : public A
{
    using A::A;
    //~B() = default; //ERROR
};

int main()
{
    std::vector< B > list;
    for( int ii = 0; ii < 3; ii++ ) { list.emplace_back(); }
    return 0;
}

Ошибка:

In file included from /usr/include/c++/5/vector:62:0,
                 from a.cpp:1:
/usr/include/c++/5/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = B; _Args = {B}]’:
/usr/include/c++/5/bits/stl_uninitialized.h:75:18:   required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<B*>; _ForwardIterator = B*; bool _TrivialValueTypes = false]’
/usr/include/c++/5/bits/stl_uninitialized.h:126:15:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<B*>; _ForwardIterator = B*]’
/usr/include/c++/5/bits/stl_uninitialized.h:281:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<B*>; _ForwardIterator = B*; _Tp = B]’
/usr/include/c++/5/bits/stl_uninitialized.h:303:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = B*; _ForwardIterator = B*; _Allocator = std::allocator<B>]’
/usr/include/c++/5/bits/vector.tcc:422:8:   required from ‘void std::vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&& ...) [with _Args = {}; _Tp = B; _Alloc = std::allocator<B>]’
/usr/include/c++/5/bits/vector.tcc:101:23:   required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = B; _Alloc = std::allocator<B>]’
a.cpp:24:57:   required from here
/usr/include/c++/5/bits/stl_construct.h:75:7: error: invalid initialization of non-const reference of type ‘B&’ from an rvalue of type ‘B’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^
a.cpp:15:8: note:   initializing argument 1 of ‘B::B(B&)’
 struct B : public A
        ^

Я использую базовый класс, как A дляуправляющие РУЧКИ, и хотят определить деструктор в производном классе в основном для целей отладки. На данный момент я использую умные указатели в векторах, чтобы избежать этой проблемы.

Мне интересно, что вызывает это и как это исправить путем изменения кода или использования более подходящего контейнера. Любая помощь приветствуется.

Редактировать: Я компилирую с g++ -std=c++11 g ++ версия g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609

Ответы [ 2 ]

10 голосов
/ 10 октября 2019

Проверьте ваши ожидания CopyConstructible и MoveConstructible с static_assert s:

static_assert(!std::is_copy_constructible<A>{});
static_assert( std::is_move_constructible<A>{});

static_assert(!std::is_copy_constructible<B>{});
static_assert(!std::is_move_constructible<B>{});

Когда объявлено ~B(), компилятор неявно удаляет B(B&&). Вы можете переопределить это поведение с помощью явного объявления:

B(B&&) = default;
1 голос
/ 10 октября 2019

Добавление чего-либо к std::vector может потенциально привести к перераспределению всего вектора. Для этого классу необходимо предоставить:

  • конструктор копирования
  • нет, кроме конструктора перемещения

Когда присутствует ~B, ваш класс B не предоставляет ни того, ни другого. С предложением using он знает, как перемещать B(A&&), но это не конструктор перемещения.

...