Are constructors bad? If so, why?

Wanted to ask Casey this on a prestream but wasn't able to catch any of them live this week, so I'll ask here:

Say that I have a struct that always gets initialized with a common pattern:

1
2
3
4
ShirleyEllis shirley;
shirley.shirley = boBirley;
shirley.bonana = fanna(foFirley);
feeFyMoMirley(&shirley);

It seems like a good idea to make an initialization function for ShirleyEllis.
1
ShirleyEllis shirley = theNameGame(boBirley, foFirley);

I am wondering why /not/ to use a constructor for this.
1
auto shirley = ShirleyEllis(boBirley, foFirley);
I think they are pretty much equivalent in terms of run-time evaluation. There's no such thing as a virtual constructor so they pretty much amount to plain old function calls.

However,

As soon as you create a constructor, C++ stops treating your struct as a C-style Plain Old Data struct and treats it as a C++ style class.

So with the ShirleyEllis(boBirley, ...); constructor created, you could no longer write:

ShirleyEllis shirley;

Without generating a compiler error. So now instead of just writing the one function you wanted, you now need to create a default constructor.

The advantage to having a constructor is that you can initialize private/protected members (which Casey is actively avoiding) as well as call superclass constructors (which Casey is also avoiding).

Using a constructor in a C-style programming scenario is a net loss.

Here's a small code snippet to demonstrate the problem.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
struct POD {
  int word;
};

struct Constructed {
  Constructed(int word) {/*logic...*/}

  int word;
};

int main() {
  POD pod; // Uninitialized.
  Constructed constructed(3);  // Works fine. Initialized
  Constructed compiler_error;  // Nope. Either delete your constructor or create a default constructor.
}


EDIT:
A corollary to no longer being able to declare Constructed without a default constructor, is that you also can't declare arrays.

1
2
POD pod_array[8]; // Valid
Constructed compiler_error_array[8]; // Invalid

Edited by Christopher on
Ah, those are some solid reasons not to use them in C++! I use D rather than C++, and D allows those cases, but I did think of another reason:
A constructor's signature is fixed, so if your constructor can fail, you would either have to throw an exception or write to some external variable errno style, whereas with an external initialization function one can do something like:
1
2
3
4
5
6
7
int init(Foo*, int bar, float baz)
{
    Foo->bar = bar;
    Foo->baz = baz;
    if(someCrazyThing() == BANANA_CAKES) return -1;
    return 0;
}


I would agree that constructors add nothing when private and protected are off the table, though they are less typing in D.

Edited by Neo Ar on
Well, for run time creation of objects they are potentially pretty bad because they have potentially more cache misses if you are creating an object that's further down a hierarchy... as code from the parent classes will be accessed as well…

Though the real cost is hard to tell. Better test it if you are unsure…

In my opinion constructors are not that bad, as long as you understand them fully, and use them in the right places. In truth I love to be able to use constructors, but there are many cases where I don't use them as well.

The other drawbacks that are mentioned here is not that big imo, you just have to be aware of them.

Edited by Gafgar (Anders Davallius) on
> Well, for run time creation of objects they are potentially pretty bad because they have potentially more cache misses if you are creating an object that's further down a hierarchy... as code from the parent classes will be accessed as well…

That's a good point.

it's not that I think they are bad per se. Just that when you are using them in a C programming style (no private/protected, no inheritance) they don't really help you out. I've noticed that when I use them and I program in a c-style it tends to be more of an annoyance. Like, "oh yeah, I need to go in and create a dummy default constructor just so I can have an array of them". It usually seems easier to make the constructor be just a function.

But it seems like you are talking about using them in a class hierarchy. that's not the situation I'm referring to, mostly because that's just not how Casey has been programming, and I was speculating that OP was wondering why Casey wasn't using them.
chebertapps

But it seems like you are talking about using them in a class hierarchy. that's not the situation I'm referring to, mostly because that's just not how Casey has been programming, and I was speculating that OP was wondering why Casey wasn't using them.


Yep, I was considering them in the absence of inheritance and private/protected.

I'll be interested to see if Jonathan Blow's language will have them or not. In D structs don't have inheritance (they are distinct from classes) and a default constructor is provided regardless of whether you provide custom constructors or not, so they are more reasonable than in C/C++.