Constructor return value?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

OK I know a constructor can't have a return value but is it feasible such that I have a class whereby
//in MyClass1.
class MyClass

MyClass1(){}
~MyClass1(){}
MyClass1(int & Result) {Result = InitMyClass()}

int InitMyClass()


//in main.cp

int main(

int result
MyClass theobject(result)
printf("The result of initializing the class is %d", result)
 
Bonj said:
OK I know a constructor can't have a return value but is it feasible
such that I have a class whereby: //in MyClass1.h
class MyClass1
{
MyClass1(){};
~MyClass1(){};
MyClass1(int & Result) {Result = InitMyClass()};

int InitMyClass();
}

//in main.cpp

int main()
{
int result;
MyClass theobject(result);
printf("The result of initializing the class is %d", result);
}

Of course it's feasible, and perfectly legal.

The Standard C++ way of indicating failure in a constructor is to throw an
exception, but there might be reasons sometimes that you don't want to do
that (the only one that comes to mind is a severe performance constraint -
exception throwing is expensive).

-cd
 
There is another reason not to throw out of a constructor: you don't know
how well or badly the object is constructed, so you can't clean up. This is
most important if the constructor allocates resources (e.g. memory)
dynamically.

e.g.

struct C
{
bool *b1, b2;
C() { b1 = b(); b2 = b();}
bool *b() { if (rand() < 0.5) throw true; else return new b; }
};

int main()
{
C* c;
try
{
c = new C();
}
catch (...)
{
// now, what might c point to? What might c->b1 or c->b2 point to?
}
return;
}
 
This situation should be handled by following the RAII principle: Resource
Acquisition Is Initialization.

struct C
{
boost::scoped_ptr<bool> b1, b2;
C() : b1(b()), b2(b()) {}
bool *b() { if (rand() < 0.5) throw true; else return new b; }
};

Now if an exception is thrown you're guaranteed that if b1 was initialized,
it'll be destructed.

-cd

Simon said:
There is another reason not to throw out of a constructor: you don't
know how well or badly the object is constructed, so you can't clean
up. This is most important if the constructor allocates resources
(e.g. memory) dynamically.

e.g.

struct C
{
bool *b1, b2;
C() { b1 = b(); b2 = b();}
bool *b() { if (rand() < 0.5) throw true; else return new b; }
};

int main()
{
C* c;
try
{
c = new C();
}
catch (...)
{
// now, what might c point to? What might c->b1 or c->b2
point to? }
return;
}

"Carl Daniel [VC++ MVP]"
Of course it's feasible, and perfectly legal.

The Standard C++ way of indicating failure in a constructor is to
throw an exception, but there might be reasons sometimes that you
don't want to do that (the only one that comes to mind is a severe
performance constraint - exception throwing is expensive).

-cd
 
Absolutely, but (unless I am thinking fuzzily as usual) that only moves it
down a peg: we can only construct members that themselves obey the RAII
principle. (If boost::scoped_ptr's constructor threw after allocating some
resource then we'd be back to square one.)

S.

Carl Daniel said:
This situation should be handled by following the RAII principle: Resource
Acquisition Is Initialization.

struct C
{
boost::scoped_ptr<bool> b1, b2;
C() : b1(b()), b2(b()) {}
bool *b() { if (rand() < 0.5) throw true; else return new b; }
};

Now if an exception is thrown you're guaranteed that if b1 was initialized,
it'll be destructed.

-cd

Simon said:
There is another reason not to throw out of a constructor: you don't
know how well or badly the object is constructed, so you can't clean
up. This is most important if the constructor allocates resources
(e.g. memory) dynamically.

e.g.

struct C
{
bool *b1, b2;
C() { b1 = b(); b2 = b();}
bool *b() { if (rand() < 0.5) throw true; else return new b; }
};

int main()
{
C* c;
try
{
c = new C();
}
catch (...)
{
// now, what might c point to? What might c->b1 or c->b2
point to? }
return;
}

"Carl Daniel [VC++ MVP]"
Bonj wrote:
OK I know a constructor can't have a return value but is it feasible
such that I have a class whereby: //in MyClass1.h
class MyClass1
{
MyClass1(){};
~MyClass1(){};
MyClass1(int & Result) {Result = InitMyClass()};

int InitMyClass();
}

//in main.cpp

int main()
{
int result;
MyClass theobject(result);
printf("The result of initializing the class is %d", result);
}

Of course it's feasible, and perfectly legal.

The Standard C++ way of indicating failure in a constructor is to
throw an exception, but there might be reasons sometimes that you
don't want to do that (the only one that comes to mind is a severe
performance constraint - exception throwing is expensive).

-cd
 
Simon said:
Absolutely, but (unless I am thinking fuzzily as usual) that only
moves it down a peg: we can only construct members that themselves
obey the RAII principle. (If boost::scoped_ptr's constructor threw
after allocating some resource then we'd be back to square one.)

Sure. But properly designed RAII containers (like boost::scoped_ptr) will
behave correctly. In the example given, the only thing that can throw is
the new expression, and if that throws boost::scoped_ptr's constructor will
never be entered. If new doesn't throw and scoped_ptr's constructor is
entered, it must either properly recover from any exception or (in reality)
promise not to throw.

-cd
 
Simon said:
Absolutely, but (unless I am thinking fuzzily as usual) that only moves it
down a peg: we can only construct members that themselves obey the RAII
principle.

Well, yes, you gotta start somewhere. :) But once you have a set of nice,
exception-safe, low-level classes such as std::string, std::vector, various
smart pointers, etc, you can build your own classes in terms of them and not
worry about them leaking.
(If boost::scoped_ptr's constructor threw after allocating some
resource then we'd be back to square one.)

That's a problem only if you have a mix of exception-safe and unsafe
members. I can't remember the last time I used a raw pointer as a class
member, and that pointer owned the data it pointed to.
 
Yep, I was not suggesting that boost::scoped_ptr behaved anything other than
properly.
 
Back
Top