2012-07-03 2 views
6

я получаю Compiler Error C2248, когда я пытаюсь скомпилировать следующий код:станда :: unique_ptr ошибка компилятора: Члены производного класса не могут получить доступ к закрытым членам базового класса

#include <list> 
#include <memory> 
using namespace std; 


class data 
{ 
public: 

    static data parse() 
    { 
     data d; 
     data::parse(d); 
     return d; 
    } 

    list<std::unique_ptr<data>> l; 

private: 

    static void parse(data& node) 
    {  } 
}; 


int main() 
{ 

    return 0; 
} 

Почему? Как я могу это исправить?

Примечание: У меня нет проблем с использованием std::shared_ptr вместо std::unique_ptr.

+1

Пожалуйста, напишите Ваше реальное сообщение об ошибке, а также достаточное количество кода, чтобы воспроизвести его. –

+0

@KerrekSB Вы можете протестировать, используя обновление, сообщение об ошибке не на английском языке, вы все равно хотите его увидеть? – Nick

+0

@JamesMcNellis VS 2012 RC – Nick

ответ

10

Вы должны обеспечить операции перемещения для вашего типа:

data(data&& other) 
    : l(std::move(other.l)) 
{ 
} 

data& operator=(data&& other) 
{ 
    l = std::move(other.l); 
    return *this; 
} 

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

data() { } 

Я понимаю, что ваш код верный как есть, в соответствии с окончательным стандартом языка C++ 11. Visual C++ не полностью реализует окончательную спецификацию, когда операции перемещения неявно генерируются (как на Visual C++ 2012 RC). Спецификация того, когда неявные операции перемещения генерируются, несколько раз очень сильно изменилась в процессе стандартизации.

Если у вас есть тип класса C, который имеет любой элемент данных, который является подвижным, но не подлежащим копированию, Visual C++ не будет генерировать неявный конструктор перемещения или переместить оператор присваивания, а неявный конструктор копирования и оператор присваивания копии будут подавлены наличие элемента данных только для перемещения. Другими словами, если вы хотите, чтобы агрегированные типы только для перемещения, вы должны предоставить операции перемещения для агрегационного класса самостоятельно.

(По крайней мере, это мое понимание от экспериментов с компилятором.)

+0

Я не знаю, что такое move ctor и переместите оператор назначения и для чего они предназначены. Вы можете мне объяснить? – Nick

+0

Если вам нужен агрегат, лучше сказать 'data() = default;'! –

+3

@KerrekSB: OP использует Visual C++, который не поддерживает дефолтные и удаленные специальные функции-члены. Если вы используете мифический компилятор, который поддерживает весь C++ 11 и не имеет ошибок, тогда ничего из этого не нужно, и код должен быть точным как есть. –

5

Прежде всего, VC++ автоматически не генерирует движение ctor и не переводит оператор присваивания, что означает, что вам нужно определить их самостоятельно.

Далее, когда вы возвращаете локальные переменные, компилятор сначала пытается выполнить переместить, прежде чем на самом деле перейдет обычный путь их копирования. Однако для этого ему нужно движение ctor. Поскольку он не имеет этого, он пытается обычную копию и через сгенерированную копию ctor автоматически вызывает конструктор копии std::list, который в свою очередь пытается вызвать копию ctor своего типа элемента, которая является частной в случае с std::unique_ptr.

Вам необходимо либо определить подходящее перемещение ctor, либо копию ctor, которая не вызывает копию std::unique_ptr (т. Е. Сделать глубокую копию содержимого).

+0

Я не знаю, что такое move ctor и переместить оператор назначения и для чего они предназначены. Вы можете мне объяснить? – Nick

+1

Я не понимаю последний параграф вашего ответа. 'return std :: move (local_variable);' неверно во всех случаях, о которых я знаю: он подавляет NRVO, и компилятор должен предпочесть перемещать операции над операциями копирования, когда они доступны (Visual C++ будет правильно выбирать конструктор перемещения в этом дело). –

+0

@James: Правильно, этот последний абзац каким-то образом пережил мое редактирование. Исправлена. – Xeo

2

Короткий ответ: (C++ 11) конкретные товары в list должны быть копируемой или movveable. A unique_ptr не может быть скопирован по дизайну, но он подвижный, если контролируемый тип также перемещается.

Ваш тип, data не движется, потому что вы не реализовали семантику перемещения, и компилятор не сделал этого для вас.

Реализовать перемещение семантику, и вы можете использовать unique_ptr в list:

data(ddata&&) {}; 

Согласно THHE стандарту, конструктор шаг будет генерироваться для вашего класса компилятором.Однако VS10 не поддерживает это - возможно, это проблема, с которой вы столкнулись.

Для получения дополнительной справки см мой пост на CR: Canonical Implementation of Move Semantics

+2

'unique_ptr' * всегда * подвижный, независимо от типа« контролируемого типа ». –

Смежные вопросы