我理解为什么在编译代码时出现C4251警告,如here中所述。我的问题是,如果可访问的出口类成员来自STL,我们是否可以忽略C4251警告?我举一个简单的例子来说明我的问题:
dll.h
#include <iostream>
#include <string>
using namespace std;
class __declspec(dllexport) HelloWorld
{
public:
string name;
HelloWorld();
HelloWorld(const string &str);
};
dll.cpp
#include "dll.h"
HelloWorld::HelloWorld()
{
name ="";
}
HelloWorld::HelloWorld(const string &str)
{
name = str;
}
我获得的警告信息如下:
Warning 1 warning C4251: 'HelloWorld::name' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'HelloWorld' *\dll.h 9
我的问题是:我可以忽略这个警告吗?我使用这个库的方式也非常简单:
#include "dll.h"
#include <iostream>
using namespace std;
int main(void)
{
HelloWorld myworld;
myworld.name = "Tom's world";
cout<<myworld.name<<endl;
return 0;
}
答案 0 :(得分:6)
要在DLL接口中公开标准C ++库的实现细节,您需要来自编译器供应商的一些保证,他们实现标准C ++库的方式是并且将保持与每个过去和将来的版本兼容。您打算使用的编译器。否则,您可能会在以后遇到非常模糊的崩溃。
这个特定供应商在这些兼容性保证的范围内是very clear:
如果从标准C ++库中的类型派生,编译调试版本(/ MTd)并且编译器错误消息引用_Container_base,则可以忽略C4251。
有关更多背景信息,请参阅this post。
所以答案是“不”。如果今天有效,明天可能会破产。
这种情况类似于医疗事故,例如在一个DLL中分配内存并在另一个DLL中释放它。
如果DLL及其所有客户端使用完全相同的编译器修订版和编译设置进行编译,并且您从未在工作例程中混合调试和发布二进制文件,则直接风险或损坏几乎为零。但是这种危险的设计习惯违背了DLL的二进制可重用性,并且可能以非显而易见且昂贵的方式限制您的未来。继续感觉被编译器警告是你可以做的最少的事情,实际上越过边缘。
答案 1 :(得分:5)
你可以忽略,但你应该明白为什么会发生这种情况以及你可能遇到的问题。
模板在编译时启动。这意味着它可能取决于您编译代码的方式。最可能改变代码的是预编译器定义(例如#define _NDEBUG或-D_NDEBUG作为命令行参数)。
如果您的DLL接口包含依赖于编译时发生的事情的对象类型,则DLL的所有客户端必须确保这些类型的代码在您的代码中编译为相同,否则可能会发生错误。 / p>
编译相同也意味着使用相同的编译器。编译器之间的差异也可以使生成的可执行文件之间的代码不同,不同的编译器通常使用不同的STL库。
我举一个例子:
template <typename T>
class A
{
int m_data;
#ifndef NDEBUG
int m_debugData;
#endif
public:
void func()
{
m_data =0;
#ifndef NDEBUG
m_debugData = 0;
#endif
}
};
在此示例中,如果使用NDEBUG编译DLL并且使用代码编译时不使用NDEBUG,则从用户代码调用func()可能会导致运行时错误。