Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #7455

Re: Virtual functions in constructors. Is it possible?

From Leo Equinox Gaspard <ekinox1995@gmail.com>
Newsgroups comp.lang.c++
Subject Re: Virtual functions in constructors. Is it possible?
Date 2011-07-04 23:59 +0200
Organization A noiseless patient Spider
Message-ID <iutd2n$d9m$1@dont-email.me> (permalink)
References (5 earlier) <iumn7a$veh$1@dont-email.me> <iumo6l$hs6$1@speranza.aioe.org> <e92f861a-e982-4dec-9f95-bf8286a15187@q1g2000vbj.googlegroups.com> <iut1gm$4dn$1@speranza.aioe.org> <iut4g4$jio$1@dont-email.me>

Show all headers | View raw


Le 04/07/2011 21:35, Alf P. Steinbach /Usenet a écrit :
> * Anonymous, on 04.07.2011 20:41:
>>
>> class VirtualBase {
>> protected:
>> class Initializer;
>> friend class Initializer;
>>
>> class Initializer {
>> public:
>>
>> Initializer() {
>> std::cout << "Initializer" << std::endl;
>> p = 0;
>> }
>>
>> ~Initializer() {
>> std::cout << "~Initializer" << std::endl;
>> if (p)
>> p->Init(); // call the virtual function
>> }
>> // might be private if VirtualBase is declared as friend...
>>
>> void Register(VirtualBase* b) const {
>> p = b;
>> }
>> private:
>> mutable VirtualBase* p;
>> // private and not implemented
>> Initializer(const Initializer&);
>> void operator =(const Initializer&);
>> };
>> public:
>>
>> VirtualBase(const Initializer& i) {
>> std::cout << "VirtualBase" << std::endl;
>> i.Register(this);
>> }
>> private:
>> virtual void Init() = 0;
>> // will be called immediately after the constructor
>> // of the most derived class
>> };
>>
>> // This is the actual hierarchy
>>
>> class Base : public virtual VirtualBase {
>> public:
>>
>> Base(const VirtualBase::Initializer& i = Initializer()) :
>> VirtualBase(i) {
>> std::cout << "Base" << std::endl;
>> }
>>
>> ~Base() {
>> std::cout << "~Base" << std::endl;
>> }
>>
>> void Init() {
>> std::cout << "Base::Init()" << std::endl;
>> }
>> };
>>
>> class Derived : public Base {
>> public:
>> // Derived() : Base() {} // compile-time error as wanted
>>
>> Derived(const VirtualBase::Initializer& i = Initializer()) :
>> Base(i), /* Base(i) is optional...*/
>> VirtualBase(i)
>> {
>> std::cout << "Derived" << std::endl;
>> }
>>
>> ~Derived() {
>> std::cout << "~Derived" << std::endl;
>> }
>>
>> void Init() {
>> std::cout << "Derived::Init()" << std::endl;
>> }
>> };
>>
>>
>> int main() {
>> Base x; // calls Base::Init
>> Derived y ; // calls Derived::Init
>> return( 0 ) ;
>> }
>
> I reworked your example to show off the memory leak problem that I
> mentioned.
>
> In addition this led me to realize one problem that I didn't think of
> earlier, namely that in the event of a failing constructor, the
> Initializer destructor will be calling a virtual method on a
> non-existent object, invoking UB.
>
> Here's the reworked code, just play with the macro symbols NO_INIT_CALL,
> FAIL_CONSTRUCTOR and FAIL_INIT:
>
>
> <code>
> #include <iostream>
> #include <stdexcept>
> #include <stdlib.h>
> using namespace std;
>
> namespace g {
> int nObjectsAllocated = 0;
> } // namespace g
>
> class VirtualBase {
> protected:
> class Initializer;
> friend class Initializer;
>
> class Initializer {
> public:
>
> Initializer() {
> cout << "Initializer" << endl;
> p = 0;
> }
>
> ~Initializer() {
> cout << "~Initializer" << endl;
> #ifndef NO_INIT_CALL
> if (p)
> p->Init(); // call the virtual function
> #endif
> }
> // might be private if VirtualBase is declared as friend...
>
> void Register(VirtualBase* b) const {
> p = b;
> }
> private:
> mutable VirtualBase* p;
> // private and not implemented
> Initializer(const Initializer&);
> void operator =(const Initializer&);
> };
> public:
>
> VirtualBase(const Initializer& i) {
> cout << "VirtualBase" << endl;
> i.Register(this);
> }
> private:
> virtual void Init() = 0;
> // will be called immediately after the constructor
> // of the most derived class
> };
>
> // This is the actual hierarchy
>
> class Base : public virtual VirtualBase {
> public:
>
> static void* operator new( size_t size )
> {
> cout << "Allocation" << endl;
> ++g::nObjectsAllocated;
> return ::operator new( size );
> }
>
> static void operator delete( void* p )
> {
> cout << "Deallocation" << endl;
> --g::nObjectsAllocated;
> return ::operator delete( p );
> }
>
> Base(const VirtualBase::Initializer& i = Initializer()) : VirtualBase(i) {
> cout << "Base" << endl;
> #ifdef FAIL_CONSTRUCTOR
> throw runtime_error( "Oops, `Base::Base` failed." );
> #endif
> }
>
> ~Base() {
> cout << "~Base" << endl;
> }
>
> void Init() {
> cout << "Base::Init()" << endl;
> #ifdef FAIL_INIT
> throw runtime_error( "Oops, `Init` failed." );
> #endif
> }
> };
>
> int main()
> {
> int result = EXIT_FAILURE;
> try
> {
> Base* p = new Base; // calls Base::Init
> cout << endl;
> delete p;
> result = EXIT_SUCCESS;
> }
> catch( exception const& x )
> {
> cerr << "!" << x.what() << endl;
> }
>
> if( g::nObjectsAllocated > 0 )
> {
> cerr << "!Memory leak." << endl;
> }
> cout << "Finished." << endl;
> return result;
> }
> </code>
>
>
> As you can see the scheme, at least in its current incarnation, is not
> very exception-friendly: invoking UB, and leaking memory.
>
> Can it be made exception safe?
>
>
> Cheers & hth.,
>
> - Alf
>

Couldn't you use, in ~Initializer :

try {
   if (p)
     p->Init();
} catch(...) {
   p->InitFailed();
   throw;
}

And implement an InitFailed() virtual method that acts as the countrary 
(not sure of the word to use there) of Init ?

So the code should have no more memory leaks.

Cheers,
Leo

Back to comp.lang.c++ | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Virtual functions in constructors. Is it possible? Anonymous <anonymous@no.net> - 2011-07-02 00:19 +0200
  Re: Virtual functions in constructors. Is it possible? "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-07-02 00:37 +0200
    Re: Virtual functions in constructors. Is it possible? Anonymous <anonymous@no.net> - 2011-07-02 01:19 +0200
      Re: Virtual functions in constructors. Is it possible? "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-07-02 08:50 +0200
        Re: Virtual functions in constructors. Is it possible? Anonymous <anonymous@no.net> - 2011-07-02 10:50 +0200
          Re: Virtual functions in constructors. Is it possible? "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-07-02 11:17 +0200
            Re: Virtual functions in constructors. Is it possible? Anonymous <anonymous@no.net> - 2011-07-02 11:25 +0200
              Re: Virtual functions in constructors. Is it possible? Anonymous <anonymous@no.net> - 2011-07-02 11:31 +0200
              Re: Virtual functions in constructors. Is it possible? "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-07-02 12:00 +0200
              Re: Virtual functions in constructors. Is it possible? Werner <werasm@gmail.com> - 2011-07-04 01:10 -0700
                Re: Virtual functions in constructors. Is it possible? Anonymous <anonymous@no.net> - 2011-07-04 20:41 +0200
                Re: Virtual functions in constructors. Is it possible? "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-07-04 21:35 +0200
                Re: Virtual functions in constructors. Is it possible? Leo Equinox Gaspard <ekinox1995@gmail.com> - 2011-07-04 23:59 +0200
                Re: Virtual functions in constructors. Is it possible? "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-07-05 11:09 +0200
                Re: Virtual functions in constructors. Is it possible? Leo Equinox Gaspard <ekinox1995@gmail.com> - 2011-07-05 13:15 +0200
                Re: Virtual functions in constructors. Is it possible? "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-07-05 14:51 +0200
                Re: Virtual functions in constructors. Is it possible? Leo Equinox Gaspard <ekinox1995@gmail.com> - 2011-07-05 19:55 +0200
                Re: Virtual functions in constructors. Is it possible? Anonymous <anonymous@no.net> - 2011-07-05 20:46 +0200
                Re: Virtual functions in constructors. Is it possible? "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-07-05 21:23 +0200
                Re: Virtual functions in constructors. Is it possible? Werner <werasm@gmail.com> - 2011-07-06 00:14 -0700
  Re: Virtual functions in constructors. Is it possible? Virchanza <virtual@lavabit.com> - 2011-07-05 14:58 -0700
    Re: Virtual functions in constructors. Is it possible? "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-07-06 01:28 +0200

csiph-web