C++ 在模块之间传递对象的替代方法

C++ 在模块之间传递对象的替代方法,c++,std,C++,Std,我的印象是,由于各种原因,在模块之间传递标准库对象(特别是模板对象)是不安全的,因为它们可以使用不同版本的标准库或不同的编译器进行编译。我现在的目标是找到一个可行的解决方案,特别是在共享指针和字符串的情况下 想到的可能解决方案包括: C和其他永不更改的基元类型(不可能,因为需要更复杂的类型) 来自标准化库的类型,可以是: 自定义实现(这需要添加字符串和此类类,听起来很可怕) 一些已经提供了此类功能的外部库(首先想到的是Boost,但即使没有涉及到的膨胀,它似乎也太重而无法工作) 一些神奇的

我的印象是,由于各种原因,在模块之间传递标准库对象(特别是模板对象)是不安全的,因为它们可以使用不同版本的标准库或不同的编译器进行编译。我现在的目标是找到一个可行的解决方案,特别是在共享指针和字符串的情况下

想到的可能解决方案包括:

  • C和其他永不更改的基元类型(不可能,因为需要更复杂的类型)
  • 来自标准化库的类型,可以是:
    • 自定义实现(这需要添加字符串和此类类,听起来很可怕)
    • 一些已经提供了此类功能的外部库(首先想到的是Boost,但即使没有涉及到的膨胀,它似乎也太重而无法工作)
  • 一些神奇的环境实际上使它变得安全(在所有情况下,但共享的情况除外)
真正的问题似乎是诸如严重依赖模板的共享指针之类的东西

关于是否传递标准库对象之类的问题已经被问过很多次了,在某些情况下总是会变成一件坏事,但是一个不涉及编写大量已经做了几十次的代码的实际解决方案似乎很少


是否有一种解决方案不涉及实现内部引用计数和自定义字符串,或者这只是为了跨版本/编译器/平台安全而必须付出的代价

假设两个模块使用相同的编译器,并且没有人将只部署一个模块的更新版本

我认为您可以跨模块(我所说的模块是指DLL+main EXE)边界传递对象,问题只在于不能依赖堆分配和静态变量

所以,如果您通过只读结构,一切都应该正常

但是一旦你开始分配、保留等等,事情就会破裂(不同的堆,没有静态)


但是可能会出错,所以请不要投反对票。

假设两个模块使用相同的编译器,并且没有人将只部署一个模块的更新版本

我认为您可以跨模块(我所说的模块是指DLL+main EXE)边界传递对象,问题只在于不能依赖堆分配和静态变量

所以,如果您通过只读结构,一切都应该正常

但是一旦你开始分配、保留等等,事情就会破裂(不同的堆,没有静态)


但是,这可能是错误的,所以请不要否决投票。

如果您使用不同的编译器编译模块,除了将类分解为它们的普通成员类型,并分别传递它们之外,没有其他解决方案。 如果您使用相同的编译器,并且只使用不同版本的编译器,那么很可能模块已经兼容(除非ABI发生了更改,如类布局等)。 此外,标准C++库类型的ABI可能已经改变,在这种情况下,可以使用第三方库来替代它,它提供了相同的功能,但保证了二进制兼容性(例如QT做到这一点)。
但这也不是一个完美的解决方案,因为主程序使用的库必须比所有模块链接的库版本更新。但这通常是足够的,因为大多数情况下,您只需要旧插件继续与新版本的程序一起工作,而不需要新插件与旧版本的程序一起工作。

除了将类分解为琐碎的成员类型,并分别传递它们之外,没有其他解决方案,如果您使用不同的编译器编译模块。 如果您使用相同的编译器,并且只使用不同版本的编译器,那么很可能模块已经兼容(除非ABI发生了更改,如类布局等)。 此外,标准C++库类型的ABI可能已经改变,在这种情况下,可以使用第三方库来替代它,它提供了相同的功能,但保证了二进制兼容性(例如QT做到这一点)。
但这也不是一个完美的解决方案,因为主程序使用的库必须比所有模块链接的库版本更新。但这通常是足够的,因为大多数情况下,您只需要旧插件继续与新版本的程序一起工作,而不需要新插件与旧版本的程序一起工作。

问题不在于在不同的模块之间传递对象,这很好。您需要强制执行的是,由模块X创建的对象总是由模块X删除

如果您为任何需要内存分配/释放的操作提供包装函数,以便您可以控制哪个模块执行这些函数,则可以实现这一点

例如,这是内存安全类的头类:

class SomeObj {
private: // private ctor/dtor to prevent outsiders from using them
    SomeObj() {}
    virtual ~SomeObj() {}
public:
    static SomeObj* create();
    void destroy();
};
以下是实施方案:

SomeObj* SomeObj::create()
{
    return new SomeObj();
}

void SomeObj::destroy()
{
    delete this;
}
通过这种方式设置类,您将强制创建或销毁对象的任何人执行
create()
destroy()
,因此具有这些函数的模块将始终管理此类的内存。请注意,
create()
destroy()
不能内联


对于像STL容器这样更复杂的类,它变得有点棘手,因为除了创建和销毁之外,您还需要包装更多的函数,但这是可以做到的。

问题不在于在不同的模块之间传递对象,这很好用。您需要强制执行的是,由模块X创建的对象总是由模块X删除

如果您为任何需要内存分配/释放的操作提供包装函数,这样您就可以控制内存分配/释放