在这种情况下我可以忽略C4251警告吗?

时间:2013-05-03 15:24:01

标签: c++ visual-studio-2010

我理解为什么在编译代码时出现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;
}

2 个答案:

答案 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()可能会导致运行时错误。