继承noncopyable对dllexport类没有影响
inheriting noncopyable has no effect in dllexport classes
UPDATE以下bug在VS2012中修复,noncopyable
正常工作
这既是一个问题,也是一种提供信息/警告他人的方式,这样他们就不会像我一样陷入同样的陷阱:似乎使用noncopyable
基类(如boost中的基类)在使用MS编译器时在导出类中没有效果。这是微软已知的bug,但我怀疑有很多程序员知道它。可以想象,这可能会产生极其严重的bug,因为它允许编写甚至不应该编译的代码。示例(此处为不可复制类的代码)
是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使得(){返回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
}
:
KB文章提到了即将发布的版本中的修复。有没有人可以检查这个问题是否已经在VS2010中修复了(或者可能是Visual Studio 11预览版)?
是否有触发任何类型错误的解决方案?我尝试(ab)使用编写
return CantCopyMe()
触发内部编译器错误的事实,但是,我找不到一种方法,只有在编译上面的MakeIt
这样的函数时才有条件地触发它。把static_assert放在noncopyable的复制构造函数中也不能删除它,因为编译器总是会编译它,即使它没有被调用。
回答1(对于VS2010),我刚刚在VS2010(带有SP1)中尝试了它,它编译得很好,这意味着它没有被修复。不幸的是,我没有2011年测试
2。我想一种方法是:
- 不再从不可复制 派生
- 在CantCopyMe中声明复制操作符和赋值操作符为私有,而不提供实现)
class CantCopyMe { public: //omitted for brevity... private: CantCopyMe( const CantCopyMe& ); const CantCopyMe& operator=( const CantCopyMe& ); };
这样做了,你就避免了你描述的危险情况,它也应该在VS2008中工作。你在正确的地方解决了这个问题,那就是在不可复制的类声明中。
我只是在一个稍微不同的情况下遇到了同样的问题:我有一个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;
}
编译器会崩溃!这是在VS2010 SP1, c++编译器版本16.00.40219.01 for 80x86.
- 为什么返回类型的'const'限定符对标有 __forceinline/内联的函数没有影响?
- 是否有任何区域设置会影响宽字符编码?
- 此分配对速度有影响吗?
- "virtual"对C++析构函数有何影响?
- 如果我对"while"块发表评论,为什么程序会死机?其中的"yield"线有何影响?
- 当在循环中使用时,std::shared_ptr 对该循环的矢量化有任何影响吗?
- 明确定义'static const variable in a struct'对C++ 11 及以上有什么影响吗?
- 每个帧的参考中都有多少性能影响
- "insert"对德克的引用有什么影响?
- 如果订购有什么影响..否则如果按概率陈述
- 预编译的标题有多少影响MFC
- 等号在大括号初始化中是否有影响?例如。 'T a = {}'与'T a{}'
- 更改静态库的"动态 RTL"设置有什么影响?
- C#:Cdecl-DllExport,参数中有一个指向类实例的指针
- 完成的线程是否对 winapi 中的主程序有影响
- 在 c++ 中使用 "this" 关键字对性能有影响吗?
- 额外的继承对对象结构或实例化有影响吗?
- 当do额外的括号有影响时,除了运算符优先级
- Array2的变化对Array(表)有影响
- try-catch对char**返回值有影响