Hacker News new | ask | show | jobs
by pyrtsa 4665 days ago
Bjarne's advice also applies to pointers wrapped as class members. There are just too many ways you can mess things up inside the class when dealing with raw pointers, examples including:

- partial construction: having to deal with already allocated pointers in case of errors during the construction - copy construction: who owns the resources? (Alternatively, you'll need to remember to disable the copy constructor explicitly.) - copy assignment: likewise

Doing the Right Thing is just so much easier when you wrap those member objects into e.g. `std::unique_ptr<T>`. That'll disable copy construction and assignment, which means that you'll need to think of that separately if it's needed.

2 comments

These are problems that pop out from a bad design choices. One of the first things I remember from OOP learning is that constructors should be as safe as they can be, which means no allocations, partial or not. Of course it is tempting to misuse the language features out of personal commodity and blame someone else. I think we can agree that a few design changes would solve the ambiguous cases. Also, for the "remembering" problem, we can inherit from a base class having all the needed restrictions in place. The std's "something_ptr" gimmicks may sound like a good compromise at first, but just like the garbage collector, these will make you lazy and neglectful over time. It's good for those to exist though.
> constructors should be as safe as they can be, which means no allocations, partial or not.

Can you expand upon what you mean by "safe" here?

If you mean "unable to fail", I vehemently disagree. Constructors should validate what is passed into them and fail if that is invalid. The alternative is to construct a zombie object that can't actually be used. Objects like this subvert the type system and lead to lots of unnecessary "if object.is_valid()" checks all over code that uses them.

"safe" like nullifying pointers and dummy-initialization for objects. This kind of initialization has a small footprint on performance, but it was made optional nevertheless, due to language's performance aims (you can skip them if you don't need that). You can make a little bit more complex operations in constructors that involve data validation, but it should only default to blank initialization if something doesn't pass the checks. The initialization that can fail (and the failure must be taken in account) should be done outside constructors. If an object is or isn't considered valid after a dummy initialization is a design decision, and likewise an adjustment in design can avoid excessive "if (object.is_valid())" kind of checks.
>That'll disable copy construction and assignment, which means that you'll need to think of that separately if it's needed.

If you have a pointer in a class that is exactly what you want to happen in most cases. Then if you want copies you "have to" define your own copy constructor and assignment operator that copy the object pointed to rather than just copying the pointer.