Странная ошибка - почему компилятор пытается вызвать конструктор копирования? - PullRequest
7 голосов
/ 31 декабря 2011

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

(118) std::map<int, layer> xs;
(119) xs.begin()->first; // error?!

layer - это не копируемый, подвижный тип.

class layer : public observable
{
    layer(const layer&);
    layer& operator=(const layer&);
public:
    layer(int index = -1);
    layer(layer&& other);
    layer& operator=(layer&& other);
   //...
};

Дляпо какой-то причине строка 119 заставила компилятор вызвать конструктор копирования для std::pair, почему?

1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(131): error C2248: 'layer::layer' : cannot access private member declared in class 'layer'
1> ..\layer.h(55) : see declaration of 'layer::layer'
1> ..\layer.h(53) : see declaration of 'layer'
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(129) : while compiling class template member function 'std::_Pair_base<_Ty1,_Ty2>::_Pair_base(const std::_Pair_base<_Ty1,_Ty2> &)'
1> with
1> [
1>     _Ty1=const int,
1>     _Ty2=layer
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(174) : see reference to class template instantiation 'std::_Pair_base<_Ty1,_Ty2>' being compiled
1> with
1> [
1>     _Ty1=const int,
1>     _Ty2=layer
1> ]
1> ..\stage.cpp(119) : see reference to class template instantiation 'std::pair<_Ty1,_Ty2>' being compiled
1> with
1> [
1>     _Ty1=const int,
1>     _Ty2=layer
1> ]

Я также попробовал следующее, где он не работает аналогичным образом.

(118) std::map<int, layer> xs;
(119) auto& t1 = *xs.begin();
(120) auto& t2 = t1.first; // error?!

Что здесь происходит?

Ответы [ 3 ]

3 голосов
/ 07 апреля 2012

Это одна из странных тонкостей ошибок шаблона. Код шаблона не является кодом, он почти ближе к языку сценариев для генерации кода. Вы даже можете иметь синтаксическую ошибку в функции, которая не обязательно вызовет ошибку компилятора, пока эта функция не будет использована (прямо или косвенно) вашим кодом.

В этом случае xs.first () вызвал генерацию std :: map :: iterator, что также требует генерации std :: pair . Реализация по умолчанию std :: pair имеет конструктор копирования, который не компилируется.

Вы можете обойти это с помощью шаблонной специализации std :: pair, у которой нет конструктора копирования, но тогда вы не можете ничего вставить в свою карту. xs [0] = myLayer создает и вставляет std :: make_pair <0, myLayer> в вашу карту, что, очевидно, требует создания копии слоя.

Типичным решением для этого является изменение вашего типа на std :: map >. Копирование shared_ptr не копирует указанный объект.

0 голосов
/ 24 января 2012

Ваш пример:

(118) std::map<int, layer> xs;
(119) xs.begin()->first; // error?!

За http://www.cplusplus.com/reference/stl/map/

xs.begin() Return iterator to beginning

... it-> first;// так же, как (* it) .first (значение ключа)

Поэтому

xs.begin()->first;

эквивалентно

pair<int,layer> piltmp = (*xs.begin());
piltmp.first;

Et voila.Копия пары на карте была создана.Что включает в себя создание копии слоя.

(Это не было бы проблемой, если бы на карте были указатели или автопоинтеры на слой, а не на сам слой.)

Теперь это не будетпроисходит, если map :: iterator :: operator-> возвращает ссылку на value_type, а не на value_type.Т.е. если он вернул lvalue, а не rvalue.Кажется странным, что это не так, но я не прошел через стандарт.

Вы можете обойти это, выполнив

pair<int,layer>& piltmp = *xs.begin();
return piltmp.first;

(не проверено).

0 голосов
/ 04 января 2012

Это зависит от того, где вы инициализируете этого участника и его первого участника. Если вы инициализируете его как статический член или в стеке без вызова конструктора, он попытается вызвать стандартный конструктор (без параметров) и не сможет получить к нему доступ, поскольку вы сделали его закрытым.

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

...