4
class Type1;
class Type2;
class __declspec(dllexport) Foo
{
  public:
    Foo();

  private:
  Type1 * m_p1;
  Type2 * m_p2;
};

Can I replace Type1 with Type3 without breaking binary compatibility?

Background: Unfortunately, this class does not use the pimpl idiom. To remedy this, I want to replace the pointer m_p1 with a pimpl-pointer.

Using Visual Studio 2010, Windows 7 and 10.

Fabian
  • 4,001
  • 4
  • 28
  • 59
  • Thank you for the comment. Added the information. – Fabian Oct 07 '19 at 08:08
  • Perhaps you could give some more background ? your Foo type is non-standard layout so just switching the compiler (even just upgrading) may break binary compatible AFAIK - this tells me you using the same compiler/machinery on both sides of the interface which seems to make the question moot. – darune Oct 07 '19 at 08:09
  • According to [20 ABI (Application Binary Interface) breaking changes every C++ developer should know](https://www.acodersjourney.com/20-abi-breaking-changes/), changing a type of any class member variable breaks the ABI. Don't know how is this site reliable though. The same information is [here](https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B%2B). – Daniel Langr Oct 07 '19 at 08:09
  • @DanielLangr: The important detail here is that I do not change `Type1` to `Type3` but `Type1 *` to `Type3 *`. The size of the types are always the same, namely the size of the pointer type. – Fabian Oct 07 '19 at 08:35
  • @darune: I use the same compiler on both sides, but one side is not under my control and so I cannot expect it to be recompiled. – Fabian Oct 07 '19 at 08:44
  • @Fabian Ty, that was what I thought, but I wan'ted to be sure. – darune Oct 07 '19 at 08:45
  • @BoBTFish As for your last sentence, I believe OP is aware that the library needs to be recompiled, but asks whether a program that uses this library (which is a _code that uses this `class`_) needs to be recompiled as well. – Daniel Langr Oct 07 '19 at 08:51
  • Right, so we need to know if the program actually uses objects of this class type in any way other that passing around pointers/references to it. Actually, I think my previous comment is more "smart-arse" than "helpful", so I'm removing it. – BoBTFish Oct 07 '19 at 08:52
  • The pointers are private, there are no getters. `Type1` and `Type2` are opaque pointers. – Fabian Oct 07 '19 at 08:54
  • @BoBTFish Do you think that creating an object of class `Foo` on the stack would be a problem? Assuming that both pointers to `Type1` and `Type3` have same size and alignment requirements? That's basically the point of the question I guess. – Daniel Langr Oct 07 '19 at 08:55

1 Answers1

2

There's no way m_p2 can be accessed on the caller side from the code example that's provided.

Even then, this is very much breaking ABI technical speaking.

But if the assumption holds (100% sure that m_p2 isn't somehow exposed) then ABI would only break if changing that type pointed to could change the layout of the class.

That would seem a little strange though - even when it's impossible to give a guarentee at the c++ language level.

Therefore it is a matter of checking wrether the layout changes between the two versions for the specific setup. That can be checked with something like:

Foo* p = 0;
&p.m_p1;//offset to m_p1 (make a static member function for the check itself)

Since there's no virtual functions on Foo we luckily do not need to worry about that for this class - otherwise that should be tested for as well to be absolutely sure.

The only thing thats left is any possible names that could be left - that would of course still be impossible to change - but in itself shouldn't break ABI.

darune
  • 10,480
  • 2
  • 24
  • 62
  • I do not understand how the check works. Do you want to measure &p.m_p1 - &p? Is sizeof helpful for such a check? – Fabian Oct 08 '19 at 04:37