2

我理解为什么在编译代码时出现 C4251 警告,如此所述。我的问题是,如果可访问的导出类成员来自 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;
}
4

2 回答 2

6

要在您的 DLL 接口中公开标准 C++ 库的实现细节,您需要编译器供应商提供一些保证,即他们实现标准 C++ 库的方式与过去和未来的每个编译器版本都保持兼容) 您打算使用的。否则,您以后可能会遇到非常模糊的崩溃。

这个特定的供应商非常清楚这些兼容性保证的范围:

如果您从标准 C++ 库中的类型派生、编译调试版本 (/MTd) 并且编译器错误消息引用 _Container_base,则可以忽略 C4251。

有关更多背景信息,您可以查阅这篇文章

所以答案是“不”。如果它今天有效,它可能明天就坏了。

这种情况类似于不当行为,例如在一个 DLL 中分配内存并在另一个 DLL 中释放它。

如果 DLL 及其所有客户端使用完全相同的编译器修订和编译设置进行编译,并且如果您从不在工作例程中混合调试和发布二进制文件,则直接风险或损坏几乎为零。但是这种危险的设计习惯违背了 DLL 的二进制可重用性,并且会以不明显和昂贵的方式限制您的未来。继续感受到编译器的警告是你对实际越界所能做的最少的事情。

于 2013-05-03T15:41:59.947 回答
6

您可以忽略,但您应该了解为什么会发生这种情况以及您可能遇到的问题。

模板在编译时启动。这意味着它可能取决于您编译代码的方式。最有可能改变代码的是预编译器定义(例如#define _NDEBUG 或-D_NDEBUG 作为命令行参数)。

如果您的 DLL 接口包含依赖于编译时发生的事情的对象类型,则 DLL 的所有客户端必须确保这些类型在其代码中的编译方式与在您的代码中相同,否则可能会发生错误。

编译相同也意味着使用相同的编译器。编译器之间的差异也会导致生成的可执行文件之间的代码不同,并且不同的编译器通常使用不同的 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
    }
};

在此示例中,如果您的 DLL 是使用 NDEBUG 编译的,而使用代码是在没有 NDEBUG 的情况下编译的,则从用户代码调用 func() 可能会导致运行时错误。

于 2013-05-03T15:35:34.623 回答