在dll接口中使用stl类时消除C4251警告的一种方法 [英] One way of eliminating C4251 warning when using stl-classes in the dll-interface

查看:876
本文介绍了在dll接口中使用stl类时消除C4251警告的一种方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在dll接口中使用stl-class不是一个好习惯,因为解释。示例给出:

  #include< iostream> 
#include< string>
#include< vector>


class __declspec(dllexport)HelloWorld
{
public:
HelloWorld()
{
abc.resize );
for(int i = 0; i <5; i ++)
abc [i] = i * 10;

str =hello the world;
}
〜HelloWorld()
{

}

std :: vector< int> abc;
std :: string str;

};

在编译此文件时,可以观察到以下警告:

 警告C4251:'HelloWorld :: str':class'std :: basic_string< _Elem,_Traits,_Ax>'需要有dll-接口'HelloWorld'
警告C4251:'HelloWorld :: abc':class'std :: vector< _Ty>'需要有类'HelloWorld'的客户端使用dll-接口

问题是如何在不使用STL类向量和字符串的情况下实现相同的功能。我可以想到的一个实现如下:

  class __declspec(dllexport)HelloWorld2 
{
public :
HelloWorld2()
{
abc_len = 5;
p_abc = new int [abc_len];
for(int i = 0; i p_abc [i] = i * 10;

std :: string temp_str(hello_the_world);
str_len = temp_str.size();
p_str = new char [str_len + 1];
strcpy(p_str,temp_str.c_str());
}
〜HelloWorld2()
{
delete [] p_abc;
delete [] p_str;
}

int * p_abc;
int abc_len;
char * p_str
int str_len;



};正如你所看到的,在新的实现中,我们使用int * p_abc来替换向量abc和char *。 p_str替换字符串str。我的问题是,是否有其他优雅的实现方法,可以做同样的。谢谢!

解决方案

我认为至少有三个可能的选项来解决这个问题:




  • 您仍然可以为字段保留STL /模板类,并将它们用作参数类型,只要将所有字段保留为私有良好的做法)。 此处是有关此问题的讨论。要删除警告,您只需使用 #pragma 语句。


  • 使用私有STL字段,并将公开的包装器类类型的字段公开给公众,但是这很可能只会将警告移动到另一个地方。


  • 请使用 PIMPL 成语在私人实现类中隐藏您的STL字段,这甚至不会


  • 或者,您可以根据C4251警告中的建议,导出所有必需的模板类专业化此处中介绍的方式。简而言之,您必须在 HelloWorld 类之前插入以下代码行:

      ... 
    #include< vector>

    模板类__declspec(dllexport)std :: allocator< int> ;;
    template class __declspec(dllexport)std :: vector< int> ;;
    template class __declspec(dllexport)std :: string;

    class __declspec(dllexport)HelloWorld
    ...

    顺便说一下,这些导出的顺序似乎很重要:向量类模板在内部使用allocator类模板,因此分配器实例化必须在向量实例化之前导出。

    / li>
  • 直接使用内在函数可能是你最糟糕的选择,但如果你封装了字段

      int * p_abc; 
    int abc_len; $ 类MyFancyDataArray 中的

      char * p_str; 
    int str_len;

    在类似 class MyFancyString 将是一个更体面的解决方案(类似于在第二点描述的解决方案)。但



可能不是最好的习惯。

It is not a good practice using stl-classes in the dll-interface as Common practice in dealing with warning c4251: class … needs to have dll-interface explains. An example is given:

#include <iostream>
#include <string>
#include <vector>


class __declspec(dllexport) HelloWorld
{
public:
    HelloWorld()
    {
        abc.resize(5);
        for(int i=0; i<5; i++)
            abc[i] = i*10;

        str="hello the world";
    }
    ~HelloWorld()
    {

    }

    std::vector<int> abc;
    std::string str;

};

When compiling this file, the following warnings can be observed:

 warning C4251: 'HelloWorld::str' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'HelloWorld'    
 warning C4251: 'HelloWorld::abc' : class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'HelloWorld'

Then the question is how we can implement the same functionality without using STL class vector and string. One implementation I could think of is as follows:

class __declspec(dllexport) HelloWorld2
{
public:
    HelloWorld2()
    {
         abc_len = 5;
         p_abc = new int [abc_len];
         for(int i=0; i<abc_len; i++)
             p_abc[i] = i*10;

         std::string temp_str("hello_the_world");
         str_len = temp_str.size();
         p_str = new char[str_len+1];
         strcpy(p_str,temp_str.c_str());
    }
    ~HelloWorld2()
    {
        delete []p_abc;
        delete []p_str;
    }

    int *p_abc;
    int abc_len;
    char *p_str;
    int str_len;



};

As you can see, in the new implementation we use int *p_abc to substitute vector abc and char *p_str to replace string str. The question I have is whether there are other elegant implementation approaches that can do the same. Thanks!

解决方案

I think you've got at least three possible options to solve this problem:

  • You could still keep STL/template classes for your fields and also use them as parameter types, as long as you keep all the fields private (which is a good practice anyway). Here is a discussion about this. To remove the warnings you could simply use according #pragma statements.

  • You could create small wrapper classes with private STL fields and expose fields of your wrapper class types to the public instead, but this would most probably only move the warnings to another places.

  • You could use the PIMPL idiom to hide your STL fields in a private implementation class, which will not even be exported from your library nor be visible outside of it.

  • Or you could actually export all the required template class specializations, as suggested in the C4251 warning, in a way that is described here. In short you would have to insert following lines of code before your HelloWorld class:

    ...
    #include <vector>
    
    template class __declspec(dllexport) std::allocator<int>;
    template class __declspec(dllexport) std::vector<int>;
    template class __declspec(dllexport) std::string;
    
    class __declspec(dllexport) HelloWorld
    ...
    

    By the way, the order of those exports seems to be important: the vector class template uses the allocator class template internally, so the allocator instantiation has to be exported before the vector instantiation.

  • The direct use of intrinsics is probably your worst option, but if you encapsulate your fields

    int *p_abc;
    int abc_len;
    

    in something like class MyFancyDataArray and the fields

    char *p_str;
    int str_len;
    

    in something like class MyFancyString, then this would be a more decent solution (similar to the one described at the second point). But it is probably not the best habit to reinvent the wheel too often.

这篇关于在dll接口中使用stl类时消除C4251警告的一种方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆