Неожиданная проблема компиляции с g ++ -std = c ++ 0x - PullRequest
8 голосов
/ 22 мая 2011

У меня есть некоторые проблемы с компиляцией, когда при компиляции с помощью g ++ -std = c ++ 0x возникают проблемы с переносом элементов типа T в вектор.

Это минимальный пример:

#include <vector>

using namespace std;

class A {
public:
    A() { }

    A& operator=(A &orig) {
        return *this;
    }
};

int main(int argc, char **argv) {
    A a;
    vector<A> b;
    A c = a; // This is fine
    b.push_back(a); // This is not, but only when compiling with -std=c++0x!
    return 0;
}

Он прекрасно компилируется с g ++ -Wall -pedantic, но выдает эту ошибку при компиляции с g ++ -Wall -pedantic -std = c ++ 0x:

 In file included from /usr/include/c++/4.4/vector:69,
                 from min.cpp:1:
/usr/include/c++/4.4/bits/vector.tcc: In member function ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, _Args&& ...) [with _Args = const A&, _Tp = A, _Alloc = std::allocator<A>]’:
/usr/include/c++/4.4/bits/stl_vector.h:741:   instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = A, _Alloc = std::allocator<A>]’
min.cpp:20:   instantiated from here
/usr/include/c++/4.4/bits/vector.tcc:314: error: no match for ‘operator=’ in ‘__position.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = A*, _Container = std::vector<A, std::allocator<A> >]() = ((const A&)((const A*)std::forward [with _Tp = const A&](((const A&)((const A*)__args#0)))))’
min.cpp:11: note: candidates are: A& A::operator=(A&)
In file included from /usr/include/c++/4.4/vector:61,
                 from min.cpp:1:
/usr/include/c++/4.4/bits/stl_algobase.h: In static member function ‘static _BI2 std::__copy_move_backward<true, false, std::random_access_iterator_tag>::__copy_move_b(_BI1, _BI1, _BI2) [with _BI1 = A*, _BI2 = A*]’:
/usr/include/c++/4.4/bits/stl_algobase.h:595:   instantiated from ‘_BI2 std::__copy_move_backward_a(_BI1, _BI1, _BI2) [with bool _IsMove = true, _BI1 = A*, _BI2 = A*]’
/usr/include/c++/4.4/bits/stl_algobase.h:605:   instantiated from ‘_BI2 std::__copy_move_backward_a2(_BI1, _BI1, _BI2) [with bool _IsMove = true, _BI1 = A*, _BI2 = A*]’
/usr/include/c++/4.4/bits/stl_algobase.h:676:   instantiated from ‘_BI2 std::move_backward(_BI1, _BI1, _BI2) [with _BI1 = A*, _BI2 = A*]’
/usr/include/c++/4.4/bits/vector.tcc:308:   instantiated from ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, _Args&& ...) [with _Args = const A&, _Tp = A, _Alloc = std::allocator<A>]’
/usr/include/c++/4.4/bits/stl_vector.h:741:   instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = A, _Alloc = std::allocator<A>]’
min.cpp:20:   instantiated from here
/usr/include/c++/4.4/bits/stl_algobase.h:561: error: no match for ‘operator=’ in ‘* -- __result = std::move [with _Tp = A&](((A&)(-- __last)))’
min.cpp:11: note: candidates are: A& A::operator=(A&)

Так что, похоже, он не находитправильный оператор = А. Почему?Почему это говорит with _Iterator = A*, когда я прохожу A?

Ответы [ 3 ]

15 голосов
/ 23 мая 2011

Требование Назначаемое , наложенное языковым стандартом на стандартные элементы контейнера, требует, чтобы выражение t = u было допустимым, даже если u является const-объектом.Это требование было определено таким образом, поскольку C ++ 98 (см. 23.1 / 4)

Вы нарушили это требование, поскольку ваш оператор присваивания не принимает const-объекты.Это сразу означает, что ваш класс A нельзя использовать в качестве типа элемента контейнера.

Почему он работал в C ++ 03, довольно не имеет значения.Это сработало случайно.Из сообщения об ошибке очевидно, что реализация библиотеки C ++ 0x использует некоторые специфические особенности C ++ 0x (например, std::move), что и делает приведенное выше требование обязательным.Но в любом случае реализация C ++ 03 (и даже реализация C ++ 98) также может не скомпилироваться для вашего A.

Ваш пример с A c = a; не имеет значения, поскольку он не используетОператор присваивания вообще (почему он здесь?).

Чтобы исправить ошибку, вы должны либо принять параметр по константной ссылке, либо по значению.

3 голосов
/ 23 мая 2011

Я совершенно уверен, что это функция безопасности. Типы с оператором назначения копирования (или конструктором копирования), которые могут изменять правую часть, не безопасны для использования в стандартных контейнерах - примером этого является (в настоящее время устарело) std::auto_ptr, которое ужасно сломается, если хранится в контейнере.

Старая реализация библиотеки C ++ 03 допускала такой небезопасный код, но, очевидно, они реализовали проверку во время компиляции в версии C ++ 0x - возможно, в сочетании с включением перемещения контейнеров.

1 голос
/ 23 мая 2011

Стандартное определение оператора назначения копирования (раздел [class.copy]):

Объявленный пользователем копия оператор присваивания X::operator= является нестатическим- функция-член класса X с ровно одним параметром типа X, X&, const X&, volatile X& или const volatile X&.

Но X& иvolatile X& варианты могут быть несовместимы с контейнерами при условии, что присвоение может быть сделано из R-значения RHS.

ПРИМЕЧАНИЕ. Передача по значению, например, X::operator=(X), является фундаментальной частью процесса копирования и замены.идиома.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...