2013-04-08 4 views
0

Ссылка Well, how does the custom deleter of std::unique_ptr work?станд :: unique_ptr пользовательских Deleter

Конструктор

std::unique_ptr<ErrorHandling> error_; 

RecursiveDescentParser::RecursiveDescentParser(std::string inputStream, bool fileService, 
      boost::optional<std::string> filePathName, std::ofstream &writer){ 

    if (fileService == true){ 
     error_(new ErrorHandling(fileService, writer)); <---- compiler error 
    } 
    else{ 
     error_(new ErrorHandling(fileService, std::ofstream())); <---- compiler error 
    }  
} 

Compiler ошибка

Error 1 error C2247: 'std::default_delete<_Ty>::operator()' not accessible because 'std::unique_ptr<_Ty>' uses 'private' to inherit from 'std::_Unique_ptr_base<_Ty,_Dx,_Empty_deleter>' 

Причина ошибки описанной here.

Я решил так 'std::default_delete<_Ty>::operator() является private, потому что дочерний класс (std::unique_ptr в данном случае) указал private inheritance, что я хотел бы написать мой собственный Deleter. Проблема в том, что мне слишком неудобно синтаксис и нотация для успеха.

+1

Является ли деструктор 'ErrorHandling' объявленным' private'? –

+0

Я фактически не объявлял деструктор (синтезированный) и формально объявлял его, но ошибка компилятора осталась. – Mushy

ответ

5

Эта линия

error_(new ErrorHandling(fileService, writer)); 

ошибка, потому что unique_ptr не имеет operator(). Сообщение об ошибке немного вводит в заблуждение, потому что у его базового класса есть один (но, к счастью, частный).

Вы, вероятно, предназначен

error_.reset(new ErrorHandling(fileService, writer)); 

что делает unique_ptr владельцем нового объекта.

+0

Даже если нет начального объекта, безопасно вызвать reset для инициализации std :: unique_ptr? – Mushy

+0

Да, используемый по умолчанию конструктор установит исходный указатель на нуль. Вполне нормально заменить это реальным указателем. –

+0

Очень интересно и спасибо. – Mushy

4

Проблема заключается в том, что вы пытаетесь использовать оператор функционального вызова на unique_ptr, что является неправильной вещью. Затем возникает некоторая путаница, потому что ваша конкретная реализация имеет недоступный оператор, а не оператор вообще, давая странное сообщение об ошибке.

Я предполагаю, что вы на самом деле пытаетесь сбросить error_ иметь новый указатель:

error_.reset(new ErrorHandling(fileService, writer)); 
// ^^^^^^ 

UPDATE: если вы хотите пользовательский Deleter (который, чтобы еще раз заявить, вы не в этой ситуации) , это может выглядеть так:

struct ErrorHandlingDeleter 
{ 
    void operator()(ErrorHandling * p) {/* do something to release the pointer */} 
}; 

std::unique_ptr<ErrorHandling, ErrorHandlingDeleter> error; 
+0

Я пытался использовать следующий синтаксис: 'std :: unique_ptr error_ (новый ErrorHandling (fileService, writer)) ;, но получил ошибку компиляции, исходя из того, что, по моему мнению, было необходимо определить для моего собственного пользовательского делетера. Несмотря на то, что использование «перезагрузки» является решением, могу ли я увидеть пример пользовательского удаления SSCCE? – Mushy

+0

@Mushy: Это синтаксис для объявления и инициализации нового уникального указателя. Однако вы не хотите этого делать; вы хотите изменить существующий, и для этого вам нужно вызвать 'reset'. 'error_ (some_pointer)' делает что-то совершенно другое - он пытается вызвать уникальный указатель как функцию, что невозможно. –

+0

@Mushy: для примера пользовательских удалений Google указал мне на http://stackoverflow.com/questions/8274451 и во многих других местах. Но, конечно, вы не хотите, чтобы пользовательский делетер здесь; они предназначены только тогда, когда 'delete' не подходит. –

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