Sign in to follow this  
speciesUnknown

in c++ classes are constructors mandatory?

Recommended Posts

speciesUnknown    527
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?

Share this post


Link to post
Share on other sites
Wavarian    850
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.

Share this post


Link to post
Share on other sites
smitty1276    560
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.

Share this post


Link to post
Share on other sites
Mike2343    1202
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.

Share this post


Link to post
Share on other sites
fpsgamer    856
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?

Share this post


Link to post
Share on other sites
BrianL    530
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.

Share this post


Link to post
Share on other sites
BrianL    530
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. :)

Share this post


Link to post
Share on other sites
Verg    450
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

Share this post


Link to post
Share on other sites
ToohrVyk    1595
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;.

Share this post


Link to post
Share on other sites
speciesUnknown    527
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.

Share this post


Link to post
Share on other sites
SymLinked    1233
Quote:
Original post by speciesUnknown
g_vector::g_vector()
{
x=0;y=0;z=1;w=1;
};

I found that this was slower than not having a constructor.


Not having a constructor would force the compiler to create one for you. Of course that's faster than initializing x, y, z and w. Why wouldn't it be?

Share this post


Link to post
Share on other sites
speciesUnknown    527
Quote:
Original post by SymLinked
Quote:
Original post by speciesUnknown
g_vector::g_vector()
{
x=0;y=0;z=1;w=1;
};

I found that this was slower than not having a constructor.


Not having a constructor would force the compiler to create one for you. Of course that's faster than initializing x, y, z and w. Why wouldn't it be?



The main question is this:
Should I always let the compiler create an empty constructor, or should i always call one of mine, or can I have a mixture of both. The answer is the conclusion i came to above. Please read the entire thread to understand.

[Edited by - speciesUnknown on August 4, 2007 9:38:12 AM]

Share this post


Link to post
Share on other sites
ToohrVyk    1595
Quote:
Original post by speciesUnknown
Should I always let the compiler create an empty constructor, or should i always call one of mine, or can I have a mixture of both. The answer is the conclusion i came to above. Please read the entire thread to understand.


I would suggest providing your own, to place the class in an initialized state. If you take a performance hit as a consequence of this, then it can only happen in a situation such as:
Vector v; // Create a default-valued vector
v = value(); // Assign a value


Because in this situation, initializing v is an additional cost with regard to not initializing it. However, this situation should not happen, and you should always prefer:
Vector v = value(); // Initialize from final value


Share this post


Link to post
Share on other sites
janta    345
Quote:
Original post by ToohrVyk
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;.


How about writing

a = b;
a += c;
a += d;


Readable *and* simple.

Share this post


Link to post
Share on other sites
Omid Ghavami    1007
Quote:
Original post by janta
Quote:
Original post by ToohrVyk
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;.


How about writing

a = b;
a += c;
a += d;


Readable *and* simple.


Doesn't solve the initial problem, it's still redundant compared to a = b + c + d

Share this post


Link to post
Share on other sites
Glak    315
Quote:
Original post by Wavarian
If you don't want to have to specify a constructor for your classes, then use a struct.


Wrong. In C++ the ONLY difference between structs and classes is default access. They are they same. Just different syntax for the same semantics. I never use the class keyword because I hate having to write "public: " in every type I define.

Share this post


Link to post
Share on other sites
joanusdmentia    1060
Quote:
Original post by Glak
Quote:
Original post by Wavarian
If you don't want to have to specify a constructor for your classes, then use a struct.


Wrong. In C++ the ONLY difference between structs and classes is default access. They are they same. Just different syntax for the same semantics


That's correct but people tend to see struct and think of a type that provides direct access to it's member variables, for example I'd make a math Vector class a 'struct' as you typically allow direct access to the individual elements of the vector, whereas I'd use a 'class' for a Window type.

As for constructors, what I typically do is provide a 'no_init' type for allowing construct in an uninitialised state (for example, with a math Vector). This allows the default construct to do the right thing (that is construct a valid, initializsed object) and also makes it perfectly clear if the vector is being left uninitialized.


struct Vector
{
// Supress initialization of the elements for the rare cases
// when the cost of default initialization is too much, it
// will be optimized into a no-op in release builds
struct no_init {};
explicit Vector(no_init) { }

// Default initialization
Vector()
: x(0.0f), y(0.0f), z(0.0f) { }
};

void func()
{
// A default initialized vector (ie. a zero vector)
Vector v1;

// An uninitialized vector
Vector v2(Vector::no_init);
}

Share this post


Link to post
Share on other sites
visitor    643
How about testing with something like:

void test_vector()
{
g_vector test_subject(12.0f, 3.0f, 9.0f, 0.0f);
test_vector=(test_vector+test_vector*96.3)/12 - test_vector; //test_vector???
}


And providing a suitable constructor:

g_vector::g_vector(float a, float b, float c, float d):
x(a), y(b), z(c), w(d)
{}


(I've added the f-s to prevent potential cast (or promotion) from int to float that might have some overhead. Also in constructors initializer list might be more optimal.)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this