【问题标题】:std::vector needs to have dll-interface to be used by clients of class 'X<T> warningstd::vector 需要有 dll 接口供类 'X<T> 警告的客户端使用
【发布时间】:2010-11-10 14:41:52
【问题描述】:

我正在尝试将我的库作为 DLL 导出,但对于使用 std::vector 的一个特定类,我收到了很多这样的警告:

template <typename T>
class AGUI_CORE_DECLSPEC AguiEvent {
    typedef void (*AguiCallbackFptr)(T arg, AguiWidget* sender);
std::vector<AguiCallbackFptr> events;
public:
    void call(AguiWidget* sender, T arg) const;
    void addHandler(AguiCallbackFptr proc);
    void removeHandler(AguiCallbackFptr proc);
    void removeHandler();
    AguiEvent();
};

我收到如下警告:

警告 57 警告 C4251: 'AguiEvent::events':类 'std::vector<_ty>' 需要有 客户端使用的dll接口 类'AguiEvent'

我试图找到如何正确执行此操作,但 MSDN 的文档非常仅限于 Windows,我需要它是跨平台的,以便它仅在 AGUI_CORE_DECLSPEC 实际定义时才执行 MS 特定的东西。

我应该怎么做才能消除这些警告?

谢谢

【问题讨论】:

标签: c++ dll


【解决方案1】:

从 DLL 导出是特定于平台的。您必须fix this for Windows(基本上在实例化的类模板上使用declspec(dllexport/dllimport))并将所需的代码封装在特定于Windows 的预处理器宏中。

我的经验是,在 Windows 上从 DLL 导出 STL 类非常痛苦,通常我会尝试将接口设计为不需要这样做。

【讨论】:

  • 关于私有类变量为什么我仍然收到此错误的任何见解?该类已导出,但我希望私有方法和对象不会触发此警告。 . .
  • 可能是因为私有的大小会影响导出类的大小。它不是公共接口的一部分,因为它不能直接访问,但如果它作为值成员在导出的类中,它仍然是它的一部分。尝试用指针握住它或躲在粉刺后面。 (所有这些都只是猜测)。
  • 链接再次断开
  • 我找不到内容 - 这次好像真的没了。将其替换为缓存副本。
【解决方案2】:

一种解决方法是依赖于 STL 结构的动态分配/解除分配。所以:

class EXPORTED ExportedClass
{
private:
    std::vector<int> *_integers;
public:
    ExportedClass()
    {
        _integers = new std::vector<int>();
    }
    ~ExportedClass()
    {
        delete _integers;
    }
};

不会发出任何警告,而且如果您分发必须与可能具有不同版本的 STL 的不同版本的编译器一起使用的相同二进制文件(dll),它会更安全。这样,您就可以 100% 保证sizeof(ExportedClass) 始终相同。

【讨论】:

  • 我猜在这种情况下也可以使用 unique_ptr 吗?我的意思是摆脱新的和删除的。
  • @AxP 它可以使用,但在分发使用 C++ 标准库编译的共享库时,您可能会遇到类似的问题,该库在共享指针上与目标系统上存在的 ABI 不兼容
【解决方案3】:

您可以只导出 dll 客户端需要访问的成员。为此,请从类声明中删除导出声明,并将其添加到您要导出的每个单独的成员函数中。

编辑:

在您的情况下,您可能不应该尝试导出该类(省略 AGUI_CORE_DECLSPEC),因为它是一个模板类。将标题中的所有方法作为内联提供,它将起作用。

如果您不希望这样,一些编译器提供了一种特殊的方式来导出模板类。但是您必须为此指定模板参数。

【讨论】:

  • 我只遇到了私人出口的问题,我对整个班级都进行了 declspec'ed。你的建议做到了!然后我在头文件中明确地声明了这些方法并且它起作用了。
【解决方案4】:

像这样处理特定于平台的东西的常用方法是尝试将所有特定于平台的设置限制为少数低级文件/类,然后使用#defines 和#ifdef/#ifndef 预处理器指令来添加/替换平台特定的变体。

为了有效地实现这一点,您可能需要一个抽象层。例如,我在 1990 年代工作的生产系统有一个“文件系统”库。这为应用程序和生产代码提供了一个通用接口,但必须依赖一些特定于平台的文件。除了使编译和维护变得更容易之外,它还使移植到新平台变得更容易。新的文件硬件供应商或操作系统风格?只需将设置添加到包含文件并相应地添加新指令。

【讨论】:

    猜你喜欢
    • 2012-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-01
    相关资源
    最近更新 更多