我的印象是,由于各种原因,当模块可以使用不同版本的标准库或不同的编译器进行编译时,在模块之间传递标准库对象(特别是模板化的对象)是不安全的。我现在的目标是找到一个可行的解决方案,特别是在共享指针和字符串的情况下。
可能的解决方案包括:
真正的问题似乎是诸如共享指针之类的东西,它们在很大程度上依赖于模板。
是否已经多次询问是否传递标准库对象等问题,并且在某些情况下总是回到糟糕的状态,但是实际的解决方案不涉及编写已经完成的大量代码时间似乎很少见。
是否有一个解决方案,不涉及实现内部引用计数和自定义字符串,或者只是为跨版本/编译器/平台安全必须支付的价格?
答案 0 :(得分:2)
如果您使用不同的编译器来编译模块,除了将类分解为简单的成员类型并单独传递它们之外,没有解决方案。 如果你使用相同的编译器并且只使用它的不同版本,那么很可能是模块已经兼容(除非ABI改变了,比如类布局等)。 除此之外,标准C ++库类型的ABI可能已经改变,在这种情况下,您可以通过使用第三方库来解决它,它提供相同的功能,但保证二进制兼容性(例如Qt这样做)。 但这也不是一个完美的解决方案,因为主程序使用的库必须比所有模块链接的库版本更新。但这通常已经足够了,因为大多数情况下,您只需要旧的插件继续使用新版本的程序,而不是新的插件可以使用旧版本的程序。
答案 1 :(得分:1)
问题不在于在不同模块之间传递对象,这很好用。您需要强制执行的是模块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容器这样的更复杂的类,它会变得有点棘手,因为除了create和destroy之外你还需要包含更多的函数,但它可以完成。
答案 2 :(得分:0)
假设两个模块使用相同的编译器,并且没有人会部署只有一个模块的更新版本......
我认为你可以跨模块传递对象(通过模块我的意思是DLLs +主要的EXE)边界,问题只在于不能依赖堆分配和静态变量。
因此,如果您传递只读结构,一切都应该没问题。
但是一旦你开始分配,保留等等,事情就会破裂(不同的堆,没有静态)。
但是可能会被误解,所以请不要下来投票。