We often use c++ structs to define data structure as opposed to class which can be a complete module with member methods. Now deep down, we know they both are the same (loosely speaking).
The fact that we often use/treat structs as data only entities creates this urge that we not add default constructors as well. But constructors are always great, they make things simpler and help eliminate errors.
Would it be frown upon if add default constructors to my data structures?
Does implementing default constructor also make the struct Non-POD (plain old data type) provided other criteria are met?
To put things in perspective, consider a simple example but in reality the struct would be much larger.
struct method
{
char name[32];
float temperature;
int duration;
};
Every time I create a method, I have to worry about (to say the least) if I forgot to set some value. Imagine I forget to set temperature
and apply the method to system which is now a random high value and causes mayhem. Or I forgot to set duration
and now the method applies itself for an unknown high duration.
Why should I take responsibility to initialize the object every time instead of implementing its constructor which guarantees it?
5
Sometimes it’s appropriate to add constructor to a struct and sometimes it is not.
Adding constructor (any constructor) to a struct prevents using aggregate initializer on it. So if you add a default constructor, you’ll also have to define non-default constructor initializing the values. But if you want to ensure that you always initialize all members, it is appropriate.
Adding constructor (any constructor, again) makes it non-POD, but in C++11 most of the rules that previously applied to POD only were changed to apply to standard layout objects and adding constructors don’t break that. So the aggregate initializer is basically the only thing you lose. But it is also often a big loss.
0
With C++11 you can do
struct method
{
char name[32] {};
float temperature = 42.141521;
int duration = -6;
};
And whenever you forget to initialize something, you get default initialization.
Quick Answer:
It depends on what do you want to achieve.
Long, Extended, Boring Answer:
You hit the nail.
I usually dislike that “C++” allows “Struct (s)” allows to declare methods. Preferably, I use explicit “Class (es)” for methods required and P.O.D. “Struct (s)” for only fields.
Yet, I agree that some basic simple operations, like:
- assign initial values (“constructor”)
- make a copy of a structure (“copy constructor)
- assign values to an existing structure (“overload assign operator”)
Are required, and, in those circumstances, methods for structures, make sense.
Suggestion
Another potential solution is to use P.O.D. structures, but, still conceptually treat them as classes and objects.
Wrap those declarations in a namespace, and, add global functions, for the most important actions.
The code declaration could be similar to this:
namespace Customers
{
struct CustomerStruct
{
char[255] FirstName;
char[255] LastName;
int Age;
bool IsAlive;
bool IsMarried;
}; // struct
CustomerStruct* CreateCustomer
(
char* NewFirstName;
char* NewLastName;
int NewAge;
bool NewIsAlive;
bool NewIsMarried;
)
{
CustomerStruct* NewCustomer = new CustomerStruct();
NewCustomer->FirstName = NewFirstName;
NewCustomer->LastName = NewLastName;
NewCustomer->Age = NewAge;
NewCustomer->IsAlive = NewIsAlive;
NewCustomer->IsMarried = NewIsMarried;
return NewCustomer;
} // CustomerStruct* CreateCustomer (...)
} // namespace
The code that applies the solution, could be something like this:
#include <Customers>
using Customers;
int main (...)
{
int ErrorCode = 0;
CustomerClass* ThisCustomer =
Customers::CreateCustomer
("John", "Doe", 23, true, true);
// do something with "ThisCustomer"
delete ThisCustomer;
return ErrorCode;
} // int main(...)
This alternative approach is better when a huge memory allocation of data is required, or interacting with other low-level shared libraries.
This approach, with some changes, is applied in Game Development.
Extra
Personally, I consider a syntax extension for “C++”, or even, a new “C++” based P.L. that solves this issue:
// "Plain Old Data" Structure
// No Methods, No "Functors", allowed
strict struct CustomerStruct
{
char[255] FirstName;
char[255] LastName;
int Age;
bool IsAlive;
bool IsMarried;
}; // strict struct
// Object Oriented "Plain Old Data" Structure
// Yes, Methods and "Functors" allowed
relaxed struct CustomerStruct
{
char[255] FirstName;
char[255] LastName;
int Age;
bool IsAlive;
bool IsMarried;
public void Foo();
public void Bar();
public (void*) (SomeFunctor) ();
}; // relaxed struct
// Class and Object Oriented
class CustomerClass
{
public char[255] FirstName;
public char[255] LastName;
public int Age;
public bool IsAlive;
public bool IsMarried;
public void Foo();
public void Bar();
}; // class
Cheers.