更新下面提到的错误已在VS2012中修复,noncopyable
正常工作
这既是一个问题,也是一种提供信息/警告他人的方式,因此它们不会像我一样陷入同样的陷阱:似乎使用noncopyable
基类(如boost中的那个)使用MS编译器时,对导出的类没有影响。这是MS a known bug,但我怀疑有很多程序员知道它。可以想象,这会产生非常讨厌的错误,因为它允许编写甚至不能编译的代码。示例(不可复制的类here的代码:)
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的复制构造函数中也不会削减它,因为编译器总是会编译它,即使它没有被调用。
答案 0 :(得分:2)
要回答1(对于VS2010),我刚刚在VS2010(带SP1)中尝试过,它编译得很好,这意味着它还没有修复。不幸的是我没有2011年测试
To 2.我想一种方法是:
class CantCopyMe { public: //omitted for brevity... private: CantCopyMe( const CantCopyMe& ); const CantCopyMe& operator=( const CantCopyMe& ); };
完成此操作后,您可以避免所描述的危险情况,也可以使用VS2008。并且您可以在正确的位置解决问题,即在不可复制的类声明中。
答案 1 :(得分:1)
我在稍微不同的情况下遇到了同样的问题:我有一个DLL导出类,它被赋予了一个不可复制的成员。 DLL导出类没有显式的复制构造函数,并且有一个Copy方法,可以在堆上返回自身的副本。添加非可复制成员时,没有编译器错误,但有一个讨厌的运行时错误。我将其跟踪到__declspec(dllexport)并发现如果我删除它,我得到了预期的正确的编译器错误,阻止了复制。考虑这个最小的例子:
#define API __declspec(dllexport)
class Inner
{
public:
Inner() {}
private:
Inner(const Inner&) {}
Inner& operator=(const Inner&) { return *this; }
};
class API Outer
{
private:
Inner i;
public:
virtual Outer* Copy()
{
return new Outer(*this);
}
};
当我用最新的VS2010编译它时,我得到:error C4716: 'Outer::Copy' : must return a value
。如果我将Copy()更改为:
virtual Outer* Copy()
{
Outer* copy = new Outer(*this);
return copy;
}
我现在只得到一个奇怪的警告:warning C4700: uninitialized local variable 'copy' used
,并且在运行时发生了令人讨厌的崩溃。最后,尝试一下:
virtual Outer* Copy()
{
Outer tmp(*this);
return nullptr;
}
编译器会崩溃!这是针对80x86的VS2010 SP1,C ++编译器版本16.00.40219.01。