2016-12-07 2 views
0

После работы с C# в течение последних десяти или двух лет мой C++ становится немного ржавым.Возвращаемый экземпляр вызывает ошибку «попытка ссылки на удаленную функцию»

Я пишу класс базы данных и имеют проблемы со следующим методом:

CRecordset CAccessDatabaseReader::ExecuteSqlQuery(LPCTSTR pszSqlQuery) 
{ 
    CRecordset recordSet(&m_Database); 
    recordSet.Open(CRecordset::forwardOnly, pszSqlQuery); 
    return CRecordset(recordSet); 
} 

Компилятор жалуется на линии с return заявлением:

Ошибка C2280 «CRecordset :: CRecordset (const CRecordset &) ': попытка ссылки на удаленную функцию

Может кто-то помочь я точно понимаю, что здесь происходит?

+1

CRecordset, как представляется, класс, не подлежащий копированию. У него нет конструктора копирования. –

+1

В C++ вы можете отключить копирование класса, и это то, что сделал CRecordset. Вот почему вы не можете вернуть его по значению. – PaulMcKenzie

+0

Чтобы «вернуть» класс на основе CObject, как это, вам, вероятно, придется использовать динамическое распределение. –

ответ

1

CRecordset конструктор копирования был явно отмечен как deleted для предотвращения копирования CRecordset объектов от одного к другому.

Таким образом, функции придется вернуть новый объект по указателю и требует, чтобы вызывающий delete объекта после завершения его использования:

CRecordset* CAccessDatabaseReader::ExecuteSqlQuery(LPCTSTR pszSqlQuery) 
{ 
    CRecordset *recordSet = new CRecordset(&m_Database); 
    if (!recordSet->Open(CRecordset::forwardOnly, pszSqlQuery)) 
    { 
     delete recordSet; 
     return NULL; // or raise an exception 
    } 
    return recordSet; 
} 

CRecordset *rs = reader.ExecuteSqlQuery(TEXT("...")); 
if (rs) 
{ 
    ... 
    delete rs; 
} 

Или лучше:

std::unique_ptr<CRecordset> CAccessDatabaseReader::ExecuteSqlQuery(LPCTSTR pszSqlQuery) 
{ 
    std::unique_ptr<CRecordset> recordSet(new CRecordset(&m_Database)); 
    if (!recordSet->Open(CRecordset::forwardOnly, pszSqlQuery)) 
     recordSet.reset(); // or raise an exception 
    return recordSet; 
} 

std::unique_ptr<CRecordset> rs = reader.ExecuteSqlQuery(TEXT("...")); 
if (rs) 
{ 
    ... 
} 
+0

Могу ли я спросить, в чем смысл возврата 'std :: unique_ptr <>'? Почему бы просто не вернуть обычный указатель, а затем указать вызывающему, указателю на переменную типа 'std :: unique_ptr <>'? Разве это не так просто? –

+0

И если вызывающий не назначает необработанный указатель классу интеллектуальных указателей? Затем вызывающий объект рискует утечкой памяти, если он забывает «удалить» указатель или неперехваченное исключение, прежде чем оно вызовет 'delete'. Функция не имеет способа узнать, что вызывающий абонент использует или не использует. Поэтому лучше говорить о том, какое управление памятью ожидается. Весь смысл использования интеллектуальных указателей - избегать подобных проблем. Это также помогает самой функции автоматически управлять памятью в случае, если что-то пойдет не так, прежде чем вызывается 'return'. –

1

CRecordset удалил свой конструктор копирования, поэтому вы не можете вернуть его по значению. Вы могли бы вернуть std::unique_ptr<CRecordset> или ссылку от ExecuteSqlQuery.

На удалении конструкторы копирования: https://stackoverflow.com/a/6077164/2449857

По возвращении из ссылки функций: Is the practice of returning a C++ reference variable, evil?

+0

Здесь нет «возврата ссылки» –

+0

@ M.M Он сказал, что пишет класс «CAccessDatabaseReader». Поэтому он может заставить 'ExecuteSqlQuery' возвращать' CRecordset & 'или 'const CRecordset &', если он делает это правильно. –

+1

Это была бы плохая идея. Например, пример 'unique_ptr' в ответе на этот поток может быть полезен. –

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