Splaty
Splaty

Reputation: 634

Initialize members in constructor with error

I'm a newbie in C++ so bear with me.

Is there a best practice for initializing members in constructors when there is no valid value to assign to the members?

For example:

device_123::device_123(data_struct_t * initData)  
{
    if(initData==NULL)
    {
       print_error(0);
       // what to initialize foo/bar to?
    }
    else
    {
      foo = initData->foo;
      bar = initData->bar; 
    }
}

In the "initData==NULL" case, is there a clean way to initialize foo & bar to say: "Hey we actually didn't get the right values assigned to us".

I know this question may sound specific to how my code implementation should interpret foo/bar, but I'm just wondering if there is a best practice out there.

Upvotes: 1

Views: 95

Answers (3)

user4581301
user4581301

Reputation: 33931

We're talking best practice here so I'm taking a hard line. There are always exceptions, but exceptions are exceptions, not best practice.

Best practices says don't allocate an object until you have the information you need to initialize an object. This is bundled in as part of Resource Allocation Is Initialization or RAII.

With RAII, when you construct an object it must come out of the constructor complete, valid and ready to use. If an object cannot be fully and properly initialized, it should be junked, discarded, obliterated, or otherwise disposed of so that there is absolutely no confusion about the state of the object. The object is either good and ready to use or does not exist.

If you do not have enough information to make the object valid, you are instantiating the object too early. If while constructing the object the input is such that the object cannot be valid, you clean up, throw an exception and the object is returned to whence it came. The creator does not get an invalid object. Ever.

RAII saves you from continually having to check something like object.isvalid() before using an object. You have an object, it's a good object. If the object wraps a resource, then that resource is available and accessible the instant you need it. You don't have to worry about trivial errors like opening a file that's not there. If you have an object, that file is open and ready for access.

As an added bonus, when properly observed RAII guarantees the resource is freed when the object goes out of scope. Static allocation (often the stack) and Smart pointers are your friend.

This requires fairly mature exception use as you won't be getting a returned error code, so the exception thrown needs to make sense for the type of error or contain an informative what string and be handled efficiently. Failure due to routine events may need to be trapped before constructing to avoid wasting time in the exception handler if performance is critical.

Upvotes: 0

Non-maskable Interrupt
Non-maskable Interrupt

Reputation: 3911

As answered above you can enforce a signature in your constructor.

There are also alternatives:

  1. when something goes wrong in constructor, throw exception
  2. do bare minimum things in constructor (zero variables) and move complex stuff to an initialization function, which you have flexibility to return more details upon failure.

Upvotes: 2

AnatolyS
AnatolyS

Reputation: 4319

If you want to be sure that your class constructor takes only valid pointer, change signature to use the reference:

class defice_123 {
public:
  defice_123(data_struct_t& initData) : foo(initData.foo), boo(initData.boo) {
  }
...
};

Upvotes: 5

Related Questions