🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

7 total messages Started by Henk Kampman Fri, 29 Sep 1995 16:26
object contruction/destruction in c++, design flaw?
#2072
Author: Henk Kampman
Date: Fri, 29 Sep 1995 16:26
79 lines
1919 bytes
Why is the destructor only called for fully contructed objects?
To my oppinion this results in code duplication in the contructor and destructor

For example:


class a
{
public:
   char* mBuffer1;
   char* mBuffer2;
   a();
   ~a();
};

a::a()
{
   mBuffer1 = NULL;
   mBuffer2 = NULL;

   try
   {
      mBuffer1 = new char[1000];
      if(mBuffer1 == NULL)
         throw MemError;

      mBuffer2 = new char[1000];
      if(mBuffer1 == NULL)
         throw MemError;
   }
   catch(...)  // allocation failed
   {
      delete mBuffer1;  
      delete mBuffer2;

      throw;
   }

}

a::~a()
{
   delete mBuffer1;
   delete mBuffer2;
}

If the destructor would be called in case of incomplete contruction, the
code would be much simpler, even in this small example.

a::a()
{
   // initialize for save destruction
   mBuffer1 = NULL;
   mBuffer2 = NULL;

   mBuffer1 = new char[1000];
   if(mBuffer1 == NULL)
      throw MemError;

   mBuffer2 = new char[1000];
   if(mBuffer1 == NULL)
      throw MemError;
 }

// this would be called in case of an exception
// if for example the mBuffer2 allocation failed
a::~a()
{
   delete mBuffer1;
   delete mBuffer2;
}

So, why not call a destructor if an object is partially contructed?

---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: object contruction/destruction in c++, des
#2073
Author: Steve Clamage
Date: Fri, 29 Sep 1995 17:26
25 lines
1617 bytes
In article 2909951146290001@huisie-ppp1.knoware.nl, henk_kampman@idsys.nl (Henk Kampman) writes:
>
>Why is the destructor only called for fully contructed objects?
>To my oppinion this results in code duplication in the contructor and destructor

If a constructor exits via an exception, those portions of the object
which were automatically constructed (base classes and members having
constructors) are automatically destroyed. I hope it is obvious that after
that point the destructor for the complete object must not be invoked.

If you choose to exit a constructor via an exception, and have created
in your own code some objects which should be destroyed, it is up to you
to destroy those objects. I don't see how an automatic mechanism could 
know what to do. (Maybe all of those objects should be destroyed, maybe
none of them should be destroyed.)
---
Steve Clamage, stephen.clamage@eng.sun.com



---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: object contruction/destruction in c++, design flaw?
#2095
Author: Fergus Henderson
Date: Mon, 02 Oct 1995 15:11
96 lines
2972 bytes
henk_kampman@idsys.nl (Henk Kampman) writes:

>Why is the destructor only called for fully contructed objects?

If the destructor were called for partially constructed objects, how
would it know which parts of the object to destroy?  This would require
the constructor first initialize all sub-objects in a way that could
not possibly throw any exceptions, and then later assign them their final
values; in many cases, this might not even be possible, and even in those
cases where it is possible, it may be inefficient.

>To my opinion this results in code duplication in the contructor and destructor

That need not be the case.  For exampe, in a lot of cases you can use
`auto_ptr' to avoid code duplication.

>class a
>{
>public:
>   char* mBuffer1;
>   char* mBuffer2;
>   a();
>   ~a();
>};

Use the following instead:

	class a {
	public:
		auto_ptr<char> mBuffer1;
		auto_ptr<char> mBuffer2;
		a();
		~a();
	}

>a::a()
>{
>   mBuffer1 = NULL;
>   mBuffer2 = NULL;
>
>   try
>   {
>      mBuffer1 = new char[1000];
>      if(mBuffer1 == NULL)
>         throw MemError;

According to the draft standard, `new' will throw an exception rather
than returning a null pointer, so the `if' statement here is unnecessary.

>      mBuffer2 = new char[1000];
>      if(mBuffer1 == NULL)
>         throw MemError;
>   }
>   catch(...)  // allocation failed
>   {
>      delete mBuffer1;  
>      delete mBuffer2;
>
>      throw;
>   }
>
>}

With auto_ptr, this becomes just

	a::a()
	{
	  mBuffer1 = new char[1000];
	  mBuffer2 = new char[1000];
	}

or alternately

	a::a()
	: mBuffer1(new char[1000]),
	  mBuffer2(new char[1000])
	{}

>a::~a()
>{
>   delete mBuffer1;
>   delete mBuffer2;
>}

With auto_ptr, you don't even need a destructor - the compiler-generated
one will do the right thing.

-- 
Fergus Henderson             |  "Australia is the richest country in the world,
fjh@cs.mu.oz.au              |   according to a new system of measuring wealth
http://www.cs.mu.oz.au/~fjh  |   announced by the World Bank yesterday."
PGP: finger fjh@128.250.37.3 |  - Melbourne newspaper "The Age", 18 Sept 1995.

[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: object contruction/destruction in c++, design flaw?
#2097
Author: J. Kanze
Date: Mon, 02 Oct 1995 15:15
95 lines
3222 bytes
Henk Kampman (henk_kampman@idsys.nl) wrote:

|> Why is the destructor only called for fully contructed objects?
|> To my oppinion this results in code duplication in the contructor and destructor

|> For example:


|> class a
|> {
|> public:
|>    char* mBuffer1;
|>    char* mBuffer2;
|>    a();
|>    ~a();
|> };

|> a::a()
|> {
|>    mBuffer1 = NULL;
|>    mBuffer2 = NULL;

|>    try
|>    {
|>       mBuffer1 = new char[1000];
|>       if(mBuffer1 == NULL) |>          throw MemError;

|>       mBuffer2 = new char[1000];
|>       if(mBuffer1 == NULL)
|>          throw MemError;
|>    }
|>    catch(...)  // allocation failed
|>    {
|>       delete mBuffer1;  
|>       delete mBuffer2;

|>       throw;
|>    }

|> }

|> a::~a()
|> {
|>    delete mBuffer1;
|>    delete mBuffer2;
|> }

Basically, the most correct way of writting this would be to change the
pointer declarations to auto_ptr, and forget the try/catch block
completely.  In fact, I would generally write it this way, with the
initialization in the initialization part of the constructor, e.g.:

    a::a()
        :   mBuffer1( new char[ 1000 ] )
        ,   mBuffer2( new char[ 1000 ] )
    {
    }

If you really insist on using pointers, then the way I would write this
would be simply:

    a::a()
    {
        mBuffer1 = new char[ 1000 ] ;
        try
        {
            mBuffer2 = new char[ 1000 ] ;
        }
        catch (...)
        {
            delete mBuffer2 ;
        }
    }

Still a lot simpler, and it works.  Note that this solution (which seems
the most natural to me) would be impossible if the destructor were to be
called on the incomplete object.

In general, for destruction of an incomplete object to work, you are
required to use special flags (like initializing the pointers to NULL);
not destructing avoids these.

(Note that compared to your examples, I do not test the results of new
for NULL.  The draft standard prohibits new from ever returning NULL,
and this behavior can be simulated with older compilers by defining a
new_handler which throws the desired exception.)
-- 
James Kanze           (+33) 88 14 49 00          email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle--
                             --Beratung in industrieller Datenverarbeitung

[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: object contruction/destruction in c++, design flaw?
#2114
Author: Lars Farm
Date: Thu, 05 Oct 1995 08:22
74 lines
3212 bytes
In article <44odn6$c61@gabi.gabi-soft.fr>,
kanze@gabi-soft.fr (J. Kanze) wrote:

>Basically, the most correct way of writting this would be to change the
>pointer declarations to auto_ptr, and forget the try/catch block
>completely.  In fact, I would generally write it this way, with the
>initialization in the initialization part of the constructor, e.g.:
>
>    a::a()
>        :   mBuffer1( new char[ 1000 ] )
>        ,   mBuffer2( new char[ 1000 ] )
>    {
>    }

In article <9527516.21208@mulga.cs.mu.OZ.AU>,
fjh@munta.cs.mu.OZ.AU (Fergus Henderson) wrote:

>With auto_ptr, this becomes just
>
>	a::a()
>	{
>	  mBuffer1 = new char[1000];
>	  mBuffer2 = new char[1000];
>	}
>
>or alternately
>
>	a::a()
>	: mBuffer1(new char[1000]),
>	  mBuffer2(new char[1000])
>	{}

[...]

>With auto_ptr, you don't even need a destructor - the compiler-generated
>one will do the right thing.

auto_ptr does delete p; not delete[] p; is this "the right thing" when you
do p = new char[1000]? If so, please disregard the rest!

	[Moderator's note: Lars Farm is right.  My suggestion was
	incorrect. -fjh.]

This demonstrates the confusion that comes from new/new[]. Other posts
defending two kinds of new have claimed that new/new[] is no problem and
users are/should/must be able to differentiate between new/new[] and
delete/delete[]. Fergus Henderson and James Kanze clearly are experts and
both experts did the same thing! If they miss this, ordinary users will
too, and much more so.

The motivation for splitting new into new/new[] is supposed to be speed and
size optimization. I would like to know what the actual quantified gain of
splitting new into new/new[] is. Can anyone quantify
(speed%,heapsize%,codesize%) the total gains in (1) a typical C++ program
and in (2) an extreme but complete working C++ program allocating lots and
lots of tiny single objects? I'm not interested in the microlevel of one
single object, but rather the effects on the entire programs.

The cost of splitting new into new/new[] is clear and demonstrated above.
Users must remember that (1) new != new[] (2) new belongs to delete not
delete[] (3) new[] belongs to delete[] not delete. (4) when to use which.

The language becomes harder to learn, use (even for experts) and teach.

If the gains turn out "small" wouldn't it be reasonable to merge new/new[]
and delete/delete[] so that new X is the same as new X[1]? Wouldn't the
simplification be worth it?

--
Lars Farm, lars.farm@nts.mh.se
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: object contruction/destruction in c++, design flaw?
#2118
Author: Joe Buck
Date: Thu, 05 Oct 1995 08:31
38 lines
1615 bytes
fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:

I've compressed Fergus's example (for writing a constructor that is
safe from out-of-memory exceptions) a bit by putting the constructor inline.
The result goes like this.

class a {
public:
	auto_ptr<char> mBuffer1;
	auto_ptr<char> mBuffer2;
	a() {
	  mBuffer1 = new char[1000];
	  mBuffer2 = new char[1000];
	}
};

Looks good; no destructor needed.  But just a minute: auto_ptr<T>'s
destructor does

	delete T;

not

	delete [] T;

right?  This means this usage is incorrect, even though it so happens
that it will work in many implementations for objects without destructors.
Shouldn't there be a separate auto_array_ptr to handle pointers to arrays
correctly?

-- 
-- Joe Buck 	<jbuck@synopsys.com>	(not speaking for Synopsys, Inc)
Anagrams for "information superhighway":	Enormous hairy pig with fan
						A rough whimper of insanity
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: object contruction/destruction in c++, design flaw?
#2119
Author: Fergus Henderson
Date: Thu, 05 Oct 1995 14:10
18 lines
1442 bytes
jbuck@Synopsys.COM (Joe Buck) writes:

>Shouldn't there be a separate auto_array_ptr to handle pointers to arrays
>correctly?

This issue has been discussed by the committee.
I agree with you, but the majority of the committee apparently disagree.
The counter-argument is that you can just use `vector' instead.

-- 
Fergus Henderson             |  "Australia is the richest country in the world,
fjh@cs.mu.oz.au              |   according to a new system of measuring wealth
http://www.cs.mu.oz.au/~fjh  |   announced by the World Bank yesterday."
PGP: finger fjh@128.250.37.3 |  - Melbourne newspaper "The Age", 18 Sept 1995.
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads