What can I do when a error occurs in Object's constructor?

Started by
89 comments, last by phresnel 13 years, 10 months ago
Quote:Original post by SiS-Shadowman
I stepped through their code and it seems shared_ptr is more sophisticated than storing a T*/U*.
They have a sp_counted_base that stores the reference counter AND an actual implementation: class sp_counted_impl_<T> : public sp_counted_base that preserves the original type.


When I think about it, then yes, there are indeed ways in C++, using interfaces and template operator overloads to approach such "magic".
Advertisement
It's pretty cool actually. Apart from some RAII classes I wrote to give me exception safe surface/vertex buffer/etc. locking objects, I haven't had to define or declare a single destructor in any of my classes.
Quote:Original post by Burnhard
It's pretty cool actually. Apart from some RAII classes I wrote to give me exception safe surface/vertex buffer/etc. locking objects, I haven't had to define or declare a single destructor in any of my classes.


I've been complaining for ages that it sucks to implement the virtual destructor for interfaces/classes, because I usually put it into a cpp file anyways (and in the case of interfaces, this means a second file). But since I use shared_ptr almost exclusively, I don't need to anymore. That's great.
Quote:Original post by SiS-Shadowman
Quote:Original post by Burnhard
It's pretty cool actually. Apart from some RAII classes I wrote to give me exception safe surface/vertex buffer/etc. locking objects, I haven't had to define or declare a single destructor in any of my classes.


I've been complaining for ages that it sucks to implement the virtual destructor for interfaces/classes, because I usually put it into a cpp file anyways (and in the case of interfaces, this means a second file). But since I use shared_ptr almost exclusively, I don't need to anymore. That's great.


For an interface, you could also make the destructor a pure virtual, then you don't need to implement it:

class Interface{public:    virtual ~Interface() = 0; // no implementation needed};


I also seem to fail how this relates with the subject at hand.

EDIT: I just read you also mean classes, which can hold data of course. In that case I find it perfectly normal to clean up what you initiated. It wouldn't be an extra file, as classes often have a .cpp file anyways (interfaces don't, but then interfaces don't have data, it'd not be an interface then, would it?). I only use smart pointers when it makes sense (reference counting etc).
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
Even better, you don't need a destructor at all, as we've been pointing out:

class Interface{public:};


:p

For me it makes sense whenever I have to carry a raw pointer around. My code contains no destructors (virtual or otherwise), no use of "delete" or "release" or "addref" at all and no use of "new" outside of factory CreateXXXX functions. These are things I see sprinkled around tutorial, sample and example code all of the time. I have a feeling they're used in a lot of production code too. As they're points of failure, I think it's not unreasonable to go the extra mile to develop methods that manage them more robustly.

Yes, it's not directly relevant to the OP, but is tangentially so.


Agreed. Proper use of RAII and smart pointers means that user-defined destructors are vanishingly rare. That's particularly the case if you use shared_ptrs with custom deleters to wrap non-ref-counted libraries you rely on.
Burnhard, your way of doing things buys you nothing but causes quite a few problems. My main issue is this though; if you are willing to sacrifice performance and flexibility to such a large degree in a bid to remove leaks, why are you using C++ instead of a garbage collected language?

THROWIFNULL(MyBar); // Not entirely unreasonable to check this, is it?


Yes it is. It means that member functions cannot be no-throw - which is a bit of a problem if you want your code to provide the strong exception guarantee.

Quote:My code contains no destructors (virtual or otherwise), no use of "delete" or "release" or "addref" at all and no use of "new" outside of factory CreateXXXX functions. These are things I see sprinkled around tutorial, sample and example code all of the time. I have a feeling they're used in a lot of production code too. As they're points of failure, I think it's not unreasonable to go the extra mile to develop methods that manage them more robustly.

I think boost/std::tr1::shared_ptr manages that robustly - I think the way you're using them introduces extra complexity / adds maintainance cost for no benefit.

I'm curious - are you using this in a team setting, or are you doing solo development?
Quote:Original post by BurnhardMy code contains no destructors (virtual or otherwise)[...]


I too agree on the use of RAII, but I'd like to point out that even if you have no raw pointers in your class you still must have a virtual destructor if instances of your class are deleted polymorphically, even if the destructor's body is completely empty.

Quote:Original post by Nitage
Burnhard, your way of doing things buys you nothing but causes quite a few problems. My main issue is this though; if you are willing to sacrifice performance and flexibility to such a large degree in a bid to remove leaks, why are you using C++ instead of a garbage collected language?
I think you far overestimate the limitations in flexibility that the use of smart pointers imposes (essentially none -- just because you don't use manual lifetime management doesn't mean you can't), and far underestimate the performance difference between refcount-based memory management and an actual GC. I'm totally NOT a fan of an Init() method, but wide use of factory functions returning smart pointers buys you out of most of C++'s manual lifetime management woes while still providing performance well ahead of full GCs.
Quote:Original post by Red Ant
I too agree on the use of RAII, but I'd like to point out that even if you have no raw pointers in your class you still must have a virtual destructor if instances of your class are deleted polymorphically, even if the destructor's body is completely empty.

Er, you should probably read the rest of the thread. shared_ptr's solution to the problem of incomplete types has the side effect of removing the need for virtual destructors, as long as the initial shared_ptr is constructed correctly.

This topic is closed to new replies.

Advertisement