Binary compatibility when using pass-by-reference instead of pass-by-pointer

This question is considered as the next question to this: What are the differences between a pointer variable and a reference variable in C ++?

After reading the answers and some further discussions that I found on stackoverflow, I know that the compiler should handle pass-by-reference in the same way it handles pass-by-pointer, and that links are nothing more than syntactic sugar. One thing that I have not been able to figure out yet if there is any difference, given binary compatibility.

In our (multi-platform) structure, we have a requirement to be binary, compatible between release builds and debugging (and between different versions of the framework). In particular, the binaries we create in debug mode should be used with release versions and vice versa. For this, we use only pure abstract classes and PODs in our interfaces.

Consider the following code:

class IMediaSerializable
{
public:
    virtual tResult Serialize(int flags,
                              ISerializer* pSerializer,
                              IException** __exception_ptr) = 0;
//[…]
};

ISerializerand IExceptionare also pure abstract classes. ISerializermust point to an existing object, so we always need to check for a NULL pointer. IExceptionimplements some kind of exception handling where the address pointed to by the pointer should be changed. For this reason, we use a pointer to a pointer, which must also be checked by a NULL pointer.

, pass-by-reference.

class IMediaSerializable
{
public:
    virtual tResult Serialize(int flags,
                              ISerializer& pSerializer,
                              IException*& __exception_ptr) = 0;
//[…]
};

, - . , .

UPDATE: : . , . , API, pass-by-reference pass-by-pointer ( ). , .

+4
3

Binary ABI . ++ ABI.

++, , .

+6

, , .

Foo, :

class Foo
{
public:
     void f(int*);
     void f(int&);
};

() f , ABI, .

, , , , .

, GCC :

void Foo::f(int*) => _ZN3Foo1fEPi
void Foo::f(int&) => _ZN3Foo1fERi

P vs R.

, , .

+2

, ABI. , , .

POD ++ 11.

++ 11 . , , " " pod.

( ).

, .

, , .

template<class T>
struct value_ptr {
  T* raw;
  // ...      
};

->clone() , , , ( ) ( unique_ptr ). unique_ptr, ->clone(). unique_ptr , .

. -, ( T* clone() const), - :

struct my_regular_foo {
  value_ptr< IFoo > ptr;
  bool some_method() const { return ptr->some_method(); } // calls pure virtual method in IFoo
};

: , , , . , , .

, .

IFoo . IFoo ( ABI (!) - ), my_regular_foo, . my_regular_foo, , , - - , , , , , , , ( ).

: IFoo ( : ), virtual , , virtual API ( , vtable vtable : - vtable . vtable , , ).

This last step - using new methods on your interfaces - can be a bridge away, since you have to explore the ABI guarantees (in practice and not) on the vtable layout for each supported compiler.

+2
source

All Articles