有没有传递类对象的值的标准过程? [英] Is there a standard procedure for passing class objects by value?

查看:121
本文介绍了有没有传递类对象的值的标准过程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有按值传递类的标准过程?换句话说,如果我这样做:

Is there a standard procedure for passing classes by value? In other words, if I do this:

struct Test
{
  int a;
  double b;
}

void DoSomething(Test t)
{
  std::cout << t.a << std::endl;
  std::cout << t.b << std::endl;
}

//...

Test myObj;
myObj.a = 5;
myObj.b = 10.5;

DoSomething(myObj);

假设标准包装和布局,标准提供了任何保证类将被发送和接收

Assuming standard packing and layout, does the standard provide any guarantees that the class will be sent and received in a consistent manner regardless of compiler?

因为我预计的问题是为什么要这样做? 。或这感觉像一个XY问题,这里(冗长的)上下文。我试图在一个EXE和使用不同的编译器编译的DLL之间来回传递一个类对象,并且看起来该类对象没有从正确的起始地址读取。但是,如果我通过引用传递对象,则此问题会蒸发。 (红利的问题 - 为什么通过引用工作,当传递的价值不会?我是在传递的值的价值会复制对象和传递一个引用的副本。显然,我误解了这里的东西。)

Because I anticipate questions along the lines of "why do you want to do this?" or "this feels like an XY problem", here's (lengthy) context. I'm attempting to pass a class object back-and-forth between an EXE and a DLL compiled with different compilers, and it appears that the class object is not being read from the correct starting address. This problem evaporates if I pass the object by reference, however. (Bonus question - why would passing by reference work when passing by value would not? I was under the impression passing by value would copy the object and pass a reference to the copy. Clearly I'm misunderstanding something here.)

推荐答案

一般来说,不同C ++编译器之间的ABI可以以任何他们认为合适的方式变化。 C ++标准不要求给定的ABI。

In general, ABI between different C++ compilers can vary in any way they see fit. The C++ standard does not mandate a given ABI.

但是,C ABI是非常稳定的。处理这个问题的一种方法是使用仅头文件函数将您的代码转换为从您的DLL导出的 externC函数。在你的DLL中, externC函数然后调用一个更传统的C ++接口。

However, C ABIs are extremely stable. One way to deal with this problem is to have header-only functions that translate your code into extern "C" functions, which are exported from your DLL. Inside your DLL the extern "C" functions then call a more conventional C++ interface.

struct Test;
// DLL exported:
extern "C" void Private_DoSomething_Exported( Test* );

// Interface:
namespace Interface {
  inline void DoSomething( Test t ) { return Private_DoSomething_Exported(&t); }
};

// implementation.  Using Test&& to make it clear that the reference is not an export parameter:
namespace Implementation {
  void DoSomething( Test&&t ) {
    std::cout << t.a << std::endl;
    std::cout << t.b << std::endl;
  }
}
void Private_DoSomething_Exported( Test* t ) {
  Assert(t);
  Implementation::DoSomething(std::move(*t));
}



这里放置了最兼容的ABI(纯CABI)在从DLL导出函数的点。客户端代码调用 Interface :: DoSomething ,其中 inline 在客户端代码中调用 C ABI(甚至不知道对象的布局),然后调用C ++ Implementation :: DoSomething

This places the "most compatible" ABI (a pure "C" ABI) at the point where you export functions from a DLL. The client code calls Interface::DoSomething, which inline in the client code calls the "C" ABI (which doesn't even know the layout of the object), which then calls a C++ Implementation::DoSomething.

这仍然不能证明每一个问题,因为甚至POD结构的布局可能会根据编译器不同(作为一个实际的例子,一些编译器处理 long 作为32位在64位机器上,其他人将 long 视为64位在64位机器上)。包装也可以有所不同。

This is still not proof against every issue, because the layout of even POD structs could vary based on compilers (as a practical example, some compilers treat long as 32 bit on 64 bit machines, others treat long as 64 bits on 64 bit machines). Packing can also vary.

为了减少这种影响,您首先要从C头文件中只使用固定大小的类型。您还需要检查两个编译器的打包文档。

To reduce that impact, you'll first want to only use fixed size types from the C header files. You'll also want to examine the packing docs of both compilers.

这篇关于有没有传递类对象的值的标准过程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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