Google
 
Webnews.only-4-geeks.com
Interesting places
news.only-4-geeks.com Forum Index » C++

How to maintain a c++ abi

 
Jump to:  
 
Brendan Miller
PostPosted: Fri Aug 22, 2008 6:49 am    Post subject: How to maintain a c++ abi
       
My question, is how does one engineer a library so as to provide a stable
c++ abi.

I was thinking that the pimpl idiom would solve a lot of problems and
allow the implementation of exposed classes to be changed easily.

Obviously templates are burned into the executable and should be made
thin wrappers around ABI stable non template code.

What isn't entirely obvious to me is how to deal with classes that export
virtual functions. If virtual functions are added,
won't this change the layout of the virtual function table and break
virtual function calls? Is there some way to add entries to the vtable
without breaking old vtable calls (i.e., adding new virtual functions
after all other virtual functions). Vtable layout is implementation
specific, but I suspect many people here have experience with how the
major implementations do it (gcc, visual studios, etc) and could provide
that information for reference.


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Martin Bonner
PostPosted: Fri Aug 22, 2008 1:03 pm    Post subject: Re: How to maintain a c++ abi
       
On Aug 22, 7:49 am, Brendan Miller <catph...@catphive.net> wrote:
Quote:
My question, is how does one engineer a library so as to provide a stable
c++ abi.
[snip]
What isn't entirely obvious to me is how to deal with classes that export
virtual functions. If virtual functions are added,
won't this change the layout of the virtual function table and break
virtual function calls? Is there some way to add entries to the vtable
without breaking old vtable calls (i.e., adding new virtual functions
after all other virtual functions).

You can't (in theory at least) change a class and have a stable ABI
(the reason is that the old client code would have one definition of
the class, and the new implementation would have another, and that
violates the one-definition-rule - which means all bets are off).

The safe way to do this, is to start with class Foo, then in version 2
you write
class Foo2 : public Foo {...};
and in version 3
class Foo3 : public Foo2 { ...}

That gets tedious very quickly (but it is reliable). Note that you
can change the definition of the Foo pimpl class, because that is held
entirely within the implementation code, and so you will replace all
definitions.

The slightly dodgy method is to add new virtual function declarations
at the end of the class definition. This will work in practise,
unless you try and make a destructor virtual in a later release
(moral: you have to decide once-and-for-all whether the destructor is
to be virtual or protected in release 1)

Note that you will /have/ to play the Foo2 game if you want to add
another constructor.

--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Marco Manfredini
PostPosted: Fri Aug 22, 2008 1:04 pm    Post subject: Re: How to maintain a c++ abi
       
Brendan Miller wrote:

Quote:
What isn't entirely obvious to me is how to deal with classes that
export virtual functions. If virtual functions are added,
won't this change the layout of the virtual function table and break
virtual function calls?
Is there some way to add entries to the vtable
without breaking old vtable calls (i.e., adding new virtual functions
after all other virtual functions). Vtable layout is implementation
specific, but I suspect many people here have experience with how the
major implementations do it (gcc, visual studios, etc) and could
provide that information for reference.

The compilers I know implement virtual function calls by indexing a
function table with a compile time constant. Adding a new member to the
end of a class definition is most likely not feasible, even if you
assume FIFO layout: Any change to the virtual layout of a base class
will shift the vtbl-slots of the derived classes.

People have various means to deal with that and other ABI-issues, for
example by defining the API as a set of abstract interface classes
(which never change once published), but may expose enhanced
functionality or different interface versions through a dynamic cast.
As a matter of fact, using this technique with C++ is a big pain in the
intestinal outlet if the interface versions are not in a clean
inheritance order, because C++ thinks that interface types are
unnecessary.

A different solution would be to have runtime-safe virtual function
calls, i.e. instead of calling member function directly from the vtbl,
a compiler generated "thunk" would be called which has a relocation
entry to resolve the right vtbl index. This is usually simulated with
the pimpl idiom, where the thunks are hand-knitted by the library
maintainer.

M
--
IYesNo yes=YesNoFactory.getFactoryInstance().YES;
yes.getDescription().equals(array[0].toUpperCase());

[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
blargg
PostPosted: Thu Aug 28, 2008 8:58 am    Post subject: Re: How to maintain a c++ abi
       
In article <1984751.OZrQRRRG3p@technoboredom.net>,
Marco Manfredini <ok_nospam_ok@phoyd.net> wrote:
Quote:
[...]
A different solution would be to have runtime-safe virtual function
calls, i.e. instead of calling member function directly from the vtbl,
a compiler generated "thunk" would be called which has a relocation
entry to resolve the right vtbl index. This is usually simulated with
the pimpl idiom, where the thunks are hand-knitted by the library
maintainer.

So you're describing something like this? No pimpl required here.

// Interface

class Base {
public:
void f();
void g();
// can add new functions without breaking already-compiled clients
private:
Base() { }
friend class Base_;
};

Base* new_derived();

// Implementation

class Base_ : public Base {
public:
Base_() { }
virtual void f();
virtual void g();
};

void Base::f() { static_cast<Base_*> (this)->f(); }
void Base::g() { static_cast<Base_*> (this)->g(); }

// except for using Base_, implementation isn't affected by insulation

class Derived : public Base_ {
public:
virtual void f();
};

Derived* new_derived() { return new Derived; }

--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

 
Yechezkel Mett
PostPosted: Thu Aug 28, 2008 8:55 pm    Post subject: Re: How to maintain a c++ abi
       
On Aug 22, 9:49 am, Brendan Miller <catph...@catphive.net> wrote:
Quote:
My question, is how does one engineer a library so as to provide a stable
c++ abi.


My preferred method is to reduce everything to a C abi and provide a
thin inline C++ wrapper on that.

e.g.:

// private to the library

class C
{
public:
void f();
void g();
};

// exported from the library

extern "C" {
C* create_C() { return new C; }
void destroy_C(C* c) { delete c; }
void C_f(C* c) { c->f(); }
void C_g(C* c) { c->g(); }
}

// thin wrapper for the user side

class C : boost::noncopyable
{
C* c;
public:
C() : c(create_C()) {}
~C() { destroy_C(c) }
void f() { c->f(); }
void g() { c-g(); }
};

Of course, if you want the class to be copyable you'll have to export
the equivalent of at least a copy constructor (you can probably do
without an assignment operator but you might want one as an
optimisation). Some care is required with the naming to avoid clashes
-- it's probably best to use a long prefix on the exported C
functions, the user doesn't use those names anyway. Take care only to
export the C functions from the library.

Concrete types such as std::string will need to be converted to C
equivalents when passing them; inward is generally not a problem, but
returning them can be a pain because you need to copy them then free
them -- you might need to return structure with a pointer to a release
function.

There is a certain amount of work involved, but it does help to
solidify the interface properly, and separate it from the
implementation, so it does have it's benefits.

This system also allows other languages to be used for one side or the
other -- I most recently used such a system for a library written in
Delphi with a program written in C++.

Yechezkel Mett


--
[ See LINK for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 

Page 1 of 1 .:.

Google
 
Webnews.only-4-geeks.com

Windows Update | C++ | C | PHP | JavaScript | Photoshop | Programming | Windows 2000 | Python | Windows XP | Object | Flash | Flash - ActionScript | Paint Shop Pro | Excel | PowerPoint | Access | Word | Windows 98 | Internet Explorer 6.0 | CorelDraw12 | Java | XML | asm x86 | Linux Mandrake | Linux RedHat | Outlook |  | news from newsgroups |_ | s

Web Templates

Awesome Website Templates ©

apteka długopisy prezenty na święta poker tracker zabawki