in c++ classes are constructors mandatory?

Started by
16 comments, last by visitor 16 years, 8 months ago
Do I need to have constructors in a class? Always? Supposing I am doing some vector maths, and I do the following: float distance_to_target = (this.position - target.position).get_length(); or supposing I use planes and points in boolean logic: if(point_vs_plane((this.position+this.direction),floor_plane))) this makes sense to me. [edited it because it actually didn't. Sorry.] If I do or don't have constructors here, what are the consequences? This kind of code is throughout my game engine. I find that by overloading operators and treating the classes as simple data types i get a slight speed boost and the maths looks more like the formulae you see in tutorials, which would otherwise complicate my learning process. My vector, ray, triangle, and line classes don't have constructors. Instead, i define them at statement scope, and let the compiler expand the code. I've heard it said that this might cause problems. Any thoughts?
Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!
Advertisement
If your classes do not have at least an empty public constructor, I find it difficult to understand how you can even have an object instance of that class (unless you're using some sort of factory which I'm guessing you're not).

If you don't want to have to specify a constructor for your classes, then use a struct.

I must say though that you could run into obscure bugs later down the track because you didn't want to use a constructor to initialize your member variables. They take 5 seconds to write and their use is considered good coding practice.
You don't have to supply a constructor unless you have specific initialization stuff you want to do. Classes and structs are pretty much the same thing, except in classes the members are private by default.
If you don't have a constructor, with MSVC at least, it will create one for you. It's empty though. Have you tested this before you asked? Just remove the constructor and compile. If it works, tada.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Let my start by saying that I don't totally understand all of your statements, but I hope to answer the best I can.

Quote:Original post by speciesUnknown
If I do or don't have constructors here, what are the consequences?


The thing is that you do have constructors in your classes. If you fail to define a constructor the compiler inserts a default empty constructor as well as a deconstructor and a default copy constructor.

So by not defining a constructor you are not in any way avoiding the cost of actually "constructing" an instance of your class.

Quote:Original post by speciesUnknown
This kind of code is throughout my game engine. I find that by overloading operators and treating the classes as simple data types i get a slight speed boost and the maths looks more like the formulae you see in tutorials, which would otherwise complicate my learning process.


Making your classes behave in logical ways is certainly making good use of C++, but I do not see how you achieved a speed boost.

Quote:Original post by speciesUnknown
My vector, ray, triangle, and line classes don't have constructors. Instead, i define them at statement scope, and let the compiler expand the code.
I've heard it said that this might cause problems.
Any thoughts?


Could you explain this line further?
As far as constructors go, there is no difference between classes and structs. Either can have a constructor and in both they are optional.

Constructors are useful, but there are cases where they can (but don't always) have measurable overhead. For example, if you construct a large number of math vectors (ie vec3_t, Vector3, etc) this can be an issue. Having such a class without a constructor is fine.

Constructors are generally required if need either an assignment operator or destructor. This isn't so much a compiler enforced rule as a general design issue.

And yes, using constructors to initialize classes can absolutely help with debugging time/stability. Making the call to not initialize a class is an optimization call that should be considered like all others - with care and measurement to insure the cost justifies the added complexity/risk.
fpsgamer, you might want to spend a bit of time looking at disassembly. Theoretically, you are correct - the compiler generated constructor should be treated the same way as an empty user constructor in a simple POD case. I've found this isn't a safe assumption on all compilers.

A more common issue is that people generally initialize members in constructors (after all, thats the main reason they are so wonderful!). For classes like vector3 like class when 99% of the uses immediately set components can actually add up.

Do a google search on 'Gamefest Unplugged (Europe) 2007: Sublime C++ For Games'. I don't know about this version of the presentation specifically, but MS has cautioned people to watch constructor cost in this series in the past.

Again to be explicit, measure, then make decisions. :)
All a constructor is intended to do for you is put your class object "in a good state." That means that nothing your class object contains, if used, could lead to undefined behavior-- like uninitialized pointers.

But although C++ gives you enough bullets to shoot yourself in the foot this way, I like to think those bullets could be "useful". Just look at each class on a case-by-case basis and decide which things need to be set into a good state.


C
my_life:          nop          jmp my_life
[ Keep track of your TDD cycle using "The Death Star" ] [ Verge Video Editor Support Forums ] [ Principles of Verg-o-nomics ] [ "t00t-orials" ]
Quote:Original post by speciesUnknown
Do I need to have constructors in a class? Always?


You need a constructor to be able to construct the class. If you don't write any, the compiler will generate a default one, which simply calls the default constructors of the base class and all the members. Note that the default constructor of POD types is a no-op (it does nothing).

Quote:Any thoughts?


You're trying to save speed in the wrong place. A typical optimization for vectors in C++ is to use expression templates. This is because, with or without inlining and/or constructors, expressions such as vector a = b + c + d; will involve creation of two temporary vectors (one per add) where none is needed. You could of course use vector a = b; (a += c) += d; but it's less readable.

With expression templates, b + c + d would not create a vector, but rather an object of type, say:
vect::wrap<vect::add<vect::add<vect::const,vect::const>,vect::const> >
This object could then be used to initialize a by effectively performing the steps a = b; (a += c) += d;. So, even though the code would still look like vector a = b + c + d;, it would act as vector a = b; (a += c) += d;.

Thanks for your replies. Some useful comments here.


Quote:
If you don't have a constructor, with MSVC at least, it will create one for you. It's empty though. Have you tested this before you asked? Just remove the constructor and compile. If it works, tada.



Ive been using my vector class without a constructor for 18 months. As yet, no bugs, but I've been using the same c++ compiler the while time, gcc 4.0.1

Quote:
Making your classes behave in logical ways is certainly making good use of C++, but I do not see how you achieved a speed boost.


When i first tested it for speed, i had the following constructor:

g_vector::g_vector()
{
x=0;y=0;z=1;w=1;
};


I found that this was slower than not having a constructor. constructor. I tested it by creating a vector, adding it to another, multiplying it by a scalar, then dividing it by a scalar, all in one statement:

void test_vector()
{
static g_vector test_subject;
test_subject.set_vector(12,3,9,0);
test_vector=(test_vector+test_vector*96.3)/12 - test_vector;
}

The code ran faster without the constructor. I didn't test it with the constructor empty, however. Its possible that the constructor being created, empty, by the compiler rather than containing four floating point assignments is the cause of the speed increase.

Quote:
And yes, using constructors to initialize classes can absolutely help with debugging time/stability. Making the call to not initialize a class is an optimization call that should be considered like all others - with care and measurement to insure the cost justifies the added complexity/risk.


quite, and I am aware of the risk. My vector class is used in other classes, which do have constructors, and which call the set_vector method to ensure the initial values don't send, for example, an NPC flying off into space at massive speeds. This is just a game engine I'm building for fun and for learning purposes, so it wont be used in any critical systems. Probably.

Quote:

With expression templates, b + c + d would not create a vector, but rather an object of type, say:
vect::wrap<vect::add<vect::add<vect::const,vect::const>,vect::const> >
This object could then be used to initialize a by effectively performing the steps a = b; (a += c) += d;. So, even though the code would still look like vector a = b + c + d;, it would act as vector a = b; (a += c) += d;.

Thanks, I'm sure thats good advice, I don't quite understand it but ill read up on expression templates.
Quote:
I must say though that you could run into obscure bugs later down the track because you didn't want to use a constructor to initialize your member variables. They take 5 seconds to write and their use is considered good coding practice.


Good practice in programming is rather like good practice in real life. Its usually slower, but much safer. Like stopping and looking left and right before crossing the road. You have to stop, but your less likely that your legs will run into "design issues".


Is the compilers creation of empty constructors and destructors a part of the language specification? If not, to ensure compatibility I think I'll have two constructors: one which takes initialization parameters, and one which is totally empty and takes no parameters.
Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!

This topic is closed to new replies.

Advertisement