Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should a C++ object always be in a valid state?

Tags:

c++

oop

Whenever an object is constructed, should the constructor always leave it in an "initialised" state?

For example, if an Image class has two constructors where one takes a file path string, and the other takes no parameters, is it bad practice for the latter to leave the image object in an invalid state?

Assuming the class is written to handle both states.

I ask this because I find it almost necessary to have a default construct in a lot of cases. Especially when an object is a member of a class and you want to initialise it IN the constructor of that class.

EDIT: I am aware of the member initialiser list. I have found a few situations where I would like to construct the object DURING the constructor of the class it is held in, not before. Although, I understand that this could potentially be more dangerous than any other alternative.

like image 553
Ben Avatar asked Mar 14 '14 15:03

Ben


2 Answers

It all boils down to the definition of a "valid state": if the methods of your class handle the state when the path is empty, then the state with the empty path is a valid state, and is definitely acceptable.

This may not be optimal from the coding perspective, though, because potentially you might need to add multiple checks for the path to be valid. You can often manage complexity by implementing the State Pattern.

I find it almost necessary to have a default construct in a lot of cases. Especially when an object is a member of a class and you want to initialise it IN the constructor of that class.

You do not need a default constructor in order to initialize an object in the constructor of the class of which it is a member, as long as you construct the dependent in the initialization list.

like image 143
Sergey Kalinichenko Avatar answered Nov 02 '22 04:11

Sergey Kalinichenko


Your last line:

I ask this because I find it almost necessary to have a default construct in a lot of cases. Especially when an object is a member of a class and you want to initialise it IN the constructor of that class.

Implies that you are not using member initializer lists. You do not need a default constructor in this case. Example:

class Member {
public:
  Member(std::string str) { std::cout << str << std::endl; }
};

class Foo {
public:
  Foo() : member_("Foo") {}
private:
  Member member_;
}

Additionally, your question title and body conflict and the terminology is a bit vague. When constructing, it is usually best to leave the object in a valid and usable state. Sometimes the second aspect (being usable) is less necessary, and many solutions require it. Further, in C++11, moving from an object must leave it in a valid state, but doesn't necessarily (and in many cases shouldn't) leave it in a usable state.

EDIT: To address your concern about doing work in your constructor, consider moving the work to either a static member of the Member class, or a private (static or non-static) function in the owning class:

class Member {
public:
  Member(std::string str) { std::cout << str << std::endl; }
};

class Foo {
public:
  Foo() : member_(CreateFoo()) {}
private:
  Member CreateMember() {
    std::string str;
    std::cin >> str;
    return Member(str);
  }
  Member member_;
};

One danger of this approach, however, is that the intialization order can be important if you use a non-static member function to do the creation. A static function is much much safer, but you may wish to pass some other pertinent member info. Remember that initialization is done in order of member declaration within the class, NOT initializer list declaration order.

like image 3
Sam Cristall Avatar answered Nov 02 '22 06:11

Sam Cristall