jwalk
jwalk

Reputation: 1147

Avoiding heap allocation with "throwing" constructors

Say I have some class Foo which does not define a default constructor and throws in a non-default constructor. When initializing a new object of the type, I'd like to catch any exceptions and return, otherwise continue using the object. I'm noticing it difficult, if at all possible, to initialize this object on the stack or through use of a shared pointer, because I'm trying to avoid managing memory.

Fail 1

Foo f; // doesn't work, no default constructor
try { f = Foo(...); }

Fail 2

try {
  Foo f(...)
}
catch(...) {}
// doesn't work, f is inaccessible

Fail 3

boost::shared_ptr<Foo> pf;
try { pf = new Foo(...); } // no assignment operator

Must I...

Foo *f;
try { f = new Foo(...) } // okay, let's just manage the memory

Is there a way?

Edit

Okay, so this works, albeit not the cleanest. Is there a more "standard" way?

boost::shared_ptr<Foo> pf;
try { pf = boost::shared_ptr<Foo>(new Foo(...)); }

Upvotes: 2

Views: 217

Answers (4)

Balog Pal
Balog Pal

Reputation: 17163

Your smart pointer case and likes work fine if you use the proper .reset() method.

However the question does not fit normal use cases, either the class is misdesigned or you use it incorrectly. Normal use should just go ahead like case#1 with F inside the block. Or without try block and leaving catch to upstream.

EDIT: Addressing recent comments as well as original issue, I keep my position that try blocks in end-user code are not welcome. For situations where I deal third-party components with certain throw strategy, if it does not fit my needs I write wrappers, converting exception to error-return or error code throwing exception. And use that extended component.

For this case the user is bothered by throwing ctor. So it would be handled by wrapping the ctor in a function:

Foo* new_foo( ARGS )
{
    try{
       return new Foo( ARGS );
    }
    catch( const FooException& )
    {
         return NULL;
    }
}

Then have the client code free of try blocks, and more importantly, free of assignments. Just const unique_ptr<Foo> p(new_foo(...)) will do.

Upvotes: 1

juanchopanza
juanchopanza

Reputation: 227420

One solution could be to use boost::optional (or C++14's std::optional):

boost::optional<Foo> f;
try { f = Foo(...); }

Upvotes: 2

The correct approach to keep f stack-based is to respect the scope:

try {
  Foo f(...);
  ... entire code using f ...
}
catch(...) {}

Upvotes: 2

syam
syam

Reputation: 15069

Smart pointers have a reset method:

boost::shared_ptr<Foo> f;
//...
f.reset(new Foo(...));

This solves your "Fail #3" and allows you to do what you want.

Upvotes: 3

Related Questions