c ++插件:跨越边界传递对象(模拟它) [英] c++ plugin : pass object across boundary (emulating it)

查看:155
本文介绍了c ++插件:跨越边界传递对象(模拟它)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于我们不应该在一个插件边界内传递除了普通旧数据结构[1]以外的任何东西,所以我想出了以下想法来传递一个对象:

Since we shouldn't pass anything else than Plain Old Data-structure[1] across a plug-in boundary, I came up with to following idea in order to pass an object :


  • 显示插件C界面中的所有公共方法,并在应用程序端将包含在对象中的插件。 (见下面的例子)

我的问题是:有更好的方法吗?
使用标准布局对象查看我的下面的编辑方式。

这是一个玩具示例,说明想法:

Here is a toy example illustrating the idea :

我想通过一个Writer跨越边界:

I want to pass a Writer across the boundary :

class Writer{
     Writer();
     virtual void write(std::string) = 0;
     ~Writer(){}
};

但是,由于兼容性问题,我们知道不应该直接完成。
这个想法是将Writer的界面作为插件中的免费函数公开:

However, we know that it shouldn't be done directly because of compatibility issue. The idea is to expose the Writer's interface as free functions in the plugin :

// plugin

extern "C"{
   Writer* create_writer(){
        return new PluginWriterImpl{}; 
   }

   void write(Writer* this_ , const char* str){
        this_->write(std::string{str});
   }

   void delete_writer(Writer* this_){
        delete this_;
   }
}

并将所有这些函数调用包装在包装器对象中在应用端:

and to wrap all those function call in a wrapper object on the application side :

// app

class WriterWrapper : public Writer{
private:
      Writer* the_plugin_writer; //object being wrapped
public:
      WriterWrapper() : the_plugin_writer{ create_writer() } 
      {}

      void write(std::string str) override{
          write(the_plugin_writer,  str.c_str() );
      }

      ~WriterWrapper(){
          delete_writer(the_plugin_writer);
      }
};

这导致了很多转发功能。 POD越过边界,应用程序不知道当前Writer的实现来自插件。

This leads to lots of forwarding function. Nothing else than POD cross the boundary, and the application doesn't know about the fact that the current Writer's implementation comes from a plugin.

[1]对于二进制兼容性问题。有关更多信息,您可以看到这个相关的SO问题: c ++插件:传递多态对象可以吗?

[1] For binary compatibility issues. For more information, you can see this related SO question : c++ plugin : Is it ok to pass polymorphic objects?

似乎我们可以通过标准布局跨越边界。如果是这样,这样的解决方案是否正确? (可以简化吗?)

It seems that we could pass standard-layout across the boundary. If so, would such a solution be correct ? (And could it be simplified ?)

我们想通过一个Writer跨越边界:

We want to pass a Writer across the boundary :

class Writer{
     Writer();
     virtual void write(std::string) = 0;
     ~Writer(){}
};

所以我们将把插件的标准布局对象传递给应用程序,并将其包装在应用程序端。

So we will pass a standard-layout object form the plugin to the app, and wrap it on the application side.

// plugin.h
struct PluginWriter{
    void write(const char* str);
};

-

// plugin_impl.cpp 

#include "plugin.h"

extern "C"{
    PluginWriter* create_writer();
    void delete_writer(PluginWriter* pw);
}

void PluginWriter::write(const char* str){
    // . . .
}

-

// app
#include "plugin.h"

class WriterWrapper : public Writer{
private:
      PluginWriter* the_plugin_writer; //object being wrapped
public:
      WriterWrapper() : the_plugin_writer{ create_writer() } 
      {}

      void write(std::string str) override{
          the_plugin_writer->write( str.c_str() );
      }

      ~WriterWrapper(){
          delete_writer(the_plugin_writer);
      }
};

但是,我担心由于#include插件,编译应用程序时链接器会抱怨。 h

However, I fear that the linker will complain while compiling the app because of the : #include plugin.h

推荐答案

在客户端和库端使用不同编译器(或甚至语言)的DLL需要二进制兼容性(也称为 ABI )。

Using a DLL with different compilers (or even languages) on client and on library side requires binary compatiblity (aka ABI).

无论说什么标准布局或POD,C ++标准不保证不同编译器之间的二进制可通用性。
对于可以确保这一点的班级成员的布局,没有全面的实施独立规则(另见此SO答案
在数据成员的相对地址上)。

Whatever is said about standard layout or POD, the C++ standard does not guarantee any binary commpatibility between different compilers. There is no comprehensive implementation independent rule on the layout of class members that could ensure this (see also this SO answer on relative address of data members ).

当然,幸运的是,在实践中许多不同的编译器在标准布局对象中使用相同的逻辑进行填充和对齐,使用
CPU架构的具体最佳实践或要求(只要不使用打包或异构对齐编译器开关)。因此,使用POD /标准布局相对安全(如Yakk
正确指出:如果您信任pod,则必须信任标准布局。

Of course, fortunately, in practice many different compilers use the same logic in standard layout objects for padding and aligning, using the specific best practices or requirements for CPU architecture (as long as no packing or exotic alignment compiler switch is used). Therefore the use of POD/standard layout is relatively safe (and as Yakk correctly pointed out: "if you trust pod, you must trust standard layout.")

所以你的代码可能正常工作。其他替代方案,依靠c ++虚拟机来避免名称变动问题,似乎也可以交叉编译器
,如这篇文章。同样的原因:在实践中,许多编译器在一个特定的OS +架构上使用一种认可的方法
来构建其vtables。但再次,这是实践观察,而不是绝对保证。

So your code may work. Other alternatives, relying on c++ virtuals to avoid name mangling issues, seem to work cross compiler as well as explained in this article. For the same reason: in practice many compilers use on one specific OS+architecture a recognized approach for constructing their vtables. But again, that's an observation from practice and not an absolute guarantee.

如果您想要为图书馆提供一个跨类似的一致性保证,那么您只应该依赖于真正的大师,而不仅仅是平常的
练习。在MS-Windows上,对象的二进制接口标准 COM 。以下是一个相关的 C ++ COM教程。可能
有点老,但没有其他的插图可以理解。

If you want to give a cross-compilar conformity guarantee for your library, then you should rely only on real gurantees and not only usual practice. On MS-Windows, the binary interface standard for objects is COM. Here is a comprenhensive C++ COM tutorial. It might be a little bit old, but no other has so many illustrations to make it understandable.

COM方法当然比您的代码片段重。但是,这是交叉编译器的成本,甚至跨越语言合规性garantee它提供。

COM approach is of course heavier than your snippet. But that's the cost of the cross compiler and even cross language compliance garantee it offers.

这篇关于c ++插件:跨越边界传递对象(模拟它)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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