ОБНОВЛЕНИЕ нижеуказанная ошибка исправлена в VS2012, и noncopyable
работает как положено
Это и вопрос, и способ предоставить информацию / предупредить других, чтобы они не попали в ту же ловушку, что и я: кажется, что используется базовый класс noncopyable
(например, в Boost) не влияет на экспортируемые классы при использовании компилятора MS. Это известная ошибка для MS, но я сомневаюсь, что многие программисты знают об этом. Как можно себе представить, это может привести к крайне неприятным ошибкам, поскольку позволяет писать код, который даже не должен компилироваться. Пример (код для некопируемого класса здесь :)
типичный заголовочный файл в проекте dll, скомпилируйте с /D EXPORT_IT
:
#ifdef EXPORT_IT
#define mydll __declspec( dllexport )
#else
#define mydll __declspec( dllimport )
#endif
class mydll CantCopyMe : private noncopyable
{
public:
CantCopyMe();
~CantCopyMe();
};
mydll CantCopyMe MakeIt();
исходный файл:
#include <iostream>
CantCopyMe::CantCopyMe()
{
std::cout << "constructor" << std::endl;
}
CantCopyMe::~CantCopyMe()
{
std::cout << "destructor" << std::endl;
}
CantCopyMe MakeIt()
{
CantCopyMe x;
return x; //oops... this sould not compile nor link but it does
}
заявка:
int main()
{
CantCopyMe x( MakeIt() );
}
выход:
constructor
destructor
destructor
1 конструктор, вызвано 2 деструктора. Представьте себе проблемы, когда класс эффективно содержит ресурсы.
редактировать
случаи использования, которые компилируются, но не должны:
CantCopyMe MakeIt()
{
CantCopyMe x;
return x;
}
void DoIt( CantCopyMe x )
{
x.Foo();
}
void SomeFun()
{
CantCopyMe x;
DoIt( x );
}
другие случаи:
CantCopyMe MakeIt ()
{
return CantCopyMe (); // фатальная ошибка C1001
}
CantCopyMe GenerateIt()
{
CantCopyMe x;
return x;
}
CantCopyMe MakeIt()
{
return GenerateIt(); //fatal error C1001
}
CantCopyMe MakeIt()
{
CantCopyMe x;
return CantCopyMe( x ); //fatal error C1001 + cl crashes
}
void DoSomething()
{
CantCopyMe x;
CantCopyMe y = x; //fatal error C1001 + cl crashes
}
Вопросы
В статье базы знаний упоминается исправление в следующем выпуске. Кто-нибудь может проверить, исправлено ли это уже в VS2010 (или, возможно, с предварительным просмотром Visual Studio 11)?
Есть ли обходной путь, чтобы вызвать любую ошибку? Я попытался (ab) использовать тот факт, что запись return CantCopyMe()
вызывает внутреннюю ошибку компилятора, но я не смог найти способ ее условного запуска только при компиляции функции, подобной MakeIt
выше. Помещение static_assert в конструктор копирования noncopyable также не обрезает его, поскольку компилятор всегда компилирует его, даже если он не вызывается.