Jump to content

  • Log In with Google      Sign In   
  • Create Account


Is that way of using constructor really better ?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
29 replies to this topic

#1 Agbahlok   Members   -  Reputation: 262

Like
0Likes
Like

Posted 03 October 2012 - 06:08 PM

Hello.
Not so long ago I started to learn D3D11 and at the moment I'm swimming through "Beginning DirectX 11 Game Programming" book. I found one thing, which I'm curious about. Author said that constructor’s member initialize list can be more efficient and is better programming practice than letting a constructor do the job in default way.

My question is as in topic, is that way of initializing members really better ?

Example from book:

D3DBase::D3DBase() : driverType_( D3D_DRIVER_TYPE_NULL ), featureLevel_( D3D_FEATURE_LEVEL_11_0 ),
                    d3dDevice_( 0 ), d3dContext_( 0 ), swapChain_( 0 ), backBufferTarget_( 0 )

Thank you in advance for any help.

Edited by Agbahlok, 03 October 2012 - 06:09 PM.


Sponsor:

#2 Bregma   Crossbones+   -  Reputation: 4365

Like
8Likes
Like

Posted 03 October 2012 - 06:48 PM

Yes.

Constructing your members with initial values is always as good as or better than constructing your members with default values and then assigning them an "initial" value later.

Why?

(1) it's often less work (cpu cycles, memory)
(2) it's often less code... the most efficient code is code you don't write
(3) your invariants are never ever violated (the object is never in an invalid state)
(4) some kinds of members, eg. references, must be initialized using an initializer list, so just do them all that way for consistency

There are some coding standards, such as the famous Google guidelines, that discourage you from initializing member variables using initializer lists. Such standards generally forbid the use of other features introduced into the language in the early 1990s and were obviously written either by a summer student or someone trying hard to sabotage the use of C++ in their organization to the benefit of their own religious language fervour. You should aim not to be one of those people.
Stephen M. Webb
Professional Free Software Developer

#3 Servant of the Lord   Crossbones+   -  Reputation: 15018

Like
9Likes
Like

Posted 03 October 2012 - 08:59 PM

Not just references, but also inherited classes must be constructed in initializer lists:
SubClass::SubClass(int blah) : BaseClass(blah) { }

With C++11 you can use "constructor delegating" (to call one constructor from another constructor) - this must also be done by initializer lists:
class MyClass()
{
	 public:
	 MyClass() : MyClass("Unnamed", 5ft + 9in, BrownColor, 160lbs) {}
	 MyClass(std::string name, Color eyeColor) : MyClass(name, 5ft + 9in, eyeColor, 160 lbs)  {}
	 MyClass(std::string name, int height, int weight) : MyClass(name, height, BrownColor, weight) {}
	 MyClass(std::string name, int height, Color eyeColor, int weight) : name(name), height(height), eyeColor(eyeColor), weight(weight) {}
}
The above is C++11 specific code.

How-so ever! Also in C++11, you get 'Non-static data member initializers'. *squeals with joy*

This will allow you to do this instead:
class MyClass()
{
	 public:
	 MyClass() :  {}
	 MyClass(std::string name, Color eyeColor) : name(name), eyeColor(eyeColor)  {}
	 MyClass(std::string name, int height, int weight) : name(name), height(height), weight(weight) {}
	 MyClass(std::string name, int height, Color eyeColor, int weight) : name(name), height(height), eyeColor(eyeColor), weight(weight) {}

	 private:
	 std::string name = "Unnamed"; //I get to do default initialization right in the class body! Sweet!
	 int height = 5ft + 9in;
	 int weight = 160lbs;
	 Color eyeColor = BrownColor;
}

Edited by Servant of the Lord, 03 October 2012 - 09:00 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#4 Cornstalks   Crossbones+   -  Reputation: 6882

Like
2Likes
Like

Posted 03 October 2012 - 11:24 PM

[edit: I was waaaay off on my original comment]

@Servant of the Lord: you should prefix literals with an underscore, as literal suffixes not starting with an underscore are reserved for future use. But thanks for reminding me that they exist!

Edited by Cornstalks, 04 October 2012 - 12:43 AM.

[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#5 Ryan_001   Prime Members   -  Reputation: 1119

Like
-2Likes
Like

Posted 04 October 2012 - 04:51 AM

Most modern compilers will optimize the trivial stuff. So I only stick important things (large items, parent classes, references, ect...) in the initializer list, as I really don't like them. My big issue is that the order items are initlialized in the initializer list is not the same order as they are listed. Which for dependent items can really lead to some hard to track down bugs.

#6 mrbastard   Members   -  Reputation: 1568

Like
2Likes
Like

Posted 04 October 2012 - 05:23 AM

My big issue is that the order items are initlialized in the initializer list is not the same order as they are listed. Which for dependent items can really lead to some hard to track down bugs.


Ah, but should initialisation be in the initialiser list order, or the order you declared them in the class declaration?

FWIW many coding standards suggest keeping your initialiser lists in the same order as your member declarations for exactly this reason.


#7 Ryan_001   Prime Members   -  Reputation: 1119

Like
0Likes
Like

Posted 04 October 2012 - 05:41 AM


My big issue is that the order items are initlialized in the initializer list is not the same order as they are listed. Which for dependent items can really lead to some hard to track down bugs.


Ah, but should initialisation be in the initialiser list order, or the order you declared them in the class declaration?

FWIW many coding standards suggest keeping your initialiser lists in the same order as your member declarations for exactly this reason.


Their order in the class definition is either for readability/clarity, or compactness/cache coherency. No one orders their variables in intialization order, at least, no one outside of C++. Not to mention dependencies can change based on the constructor that is chosen. If the order of initialization occurs in order of the intialization list, then at least you have some control in regards to dependencies. Course IMO the best solution is just to use intializtion lists when absolutely necessary, use standard C++ code the rest of the time.

#8 jbadams   Senior Staff   -  Reputation: 14936

Like
6Likes
Like

Posted 04 October 2012 - 05:46 AM

use intializtion lists when absolutely necessary, use standard C++ code the rest of the time.

The initializer lists are standard C++ code.

#9 Bregma   Crossbones+   -  Reputation: 4365

Like
5Likes
Like

Posted 04 October 2012 - 07:20 AM


My big issue is that the order items are initlialized in the initializer list is not the same order as they are listed. Which for dependent items can really lead to some hard to track down bugs.


Ah, but should initialisation be in the initialiser list order, or the order you declared them in the class declaration?

FWIW many coding standards suggest keeping your initialiser lists in the same order as your member declarations for exactly this reason.

That, and because the language standard clearly and unambiguously specifies that member data is initialized in the order of declaration regardless of the order in which they appear in initializer lists. If there is a compiler that does not issue a warning when you put initializers out of order, you should switch to one that does. If you ignore the warnings the compiler gives you, blame only yourself.

If your coding standards suggest you write bad code, consider dropping that standard.

Consider also that if other people have to maintain your code, and they have become used to good practices such as initializing all member data in initializer lists, then you increase the maintenance cost of your software.
Stephen M. Webb
Professional Free Software Developer

#10 clb   Members   -  Reputation: 1661

Like
0Likes
Like

Posted 04 October 2012 - 08:22 AM

One gotcha though related to initializer lists is that exception safety is not possible if allocating memory to raw pointers.

Consider
Bar::Bar()
{
   throw SomeException();
}

class Foo
{
   int *somePointer;
   Bar bar;
};

Foo::Foo()
:somePointer(new int[10])
{
}

Foo::~Foo()
{
   delete[] somePointer;
}

The above code has a memory leak, somePointer is never freed since construction of Bar throws an exception.

Edited by clb, 04 October 2012 - 08:22 AM.

Me+PC=clb.demon.fi | C++ Math and Geometry library: MathGeoLib, test it live! | C++ Game Networking: kNet | 2D Bin Packing: RectangleBinPack | Use gcc/clang/emcc from VS: vs-tool | Resume+Portfolio | gfxapi, test it live!

#11 SiCrane   Moderators   -  Reputation: 9158

Like
8Likes
Like

Posted 04 October 2012 - 08:38 AM

No, it's possible to handle that case, it's just ugly, annoying and doesn't scale well.
Foo::Foo()
try : somePointer(new int[10])
{
  // constructor body
} catch (SomeException & s) {
  delete [] somePointer;
  throw;
}


#12 Bregma   Crossbones+   -  Reputation: 4365

Like
7Likes
Like

Posted 04 October 2012 - 09:52 AM

One gotcha though related to initializer lists is that exception safety is not possible if allocating memory to raw pointers.

....

The above code has a memory leak, somePointer is never freed since construction of Bar throws an exception.

It's true that you can write bad code in any language. In this case, the language is C.

The C++ answer to that is do not use C-style raw pointers.
Bar::Bar()
{
   throw SomeException();
}

class Foo
{
   std::unique_ptr<int[]> somePointer;
   Bar bar;
};

Foo::Foo()
:somePointer(new int[10])
{
}

Foo::~Foo()
{
}
Wow, less code, exception safe.

Of course, there's the response "but I prefer to write bad code and bad code doesn't work, therefore C++ is bad", but all that kind of argument does for me is make me respect you less.
Stephen M. Webb
Professional Free Software Developer

#13 Servant of the Lord   Crossbones+   -  Reputation: 15018

Like
7Likes
Like

Posted 04 October 2012 - 10:50 AM

The C++ answer to that is do not use C-style raw pointers.

QFT.

Of course, there's the response "but I prefer to write bad code and bad code doesn't work, therefore C++ is bad"


"I get my hands dirty when I try to garden without a shovel!"
Then use a shovel! It's sitting two feet away from you...
"C++ is bad, because it lets you dig with your hands if you want to. *My* language glues the shovel to your hands."

C++ isn't intended to, nor designed for, protecting users from themselves.
Now excuse me while I go try to make a pot of coffee with a shovel still glued to my hands.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#14 mrbastard   Members   -  Reputation: 1568

Like
2Likes
Like

Posted 04 October 2012 - 12:18 PM

If there is a compiler that does not issue a warning when you put initializers out of order, you should switch to one that does.


FYI Visual c++ 2012 does not issue a warning about this with /wall (and 'language extensions' disabled fwiw). I know gcc does, and I agree that it's a useful warning.


#15 tanzanite7   Members   -  Reputation: 1007

Like
0Likes
Like

Posted 04 October 2012 - 02:52 PM

	 int height = 5ft + 9in;
	 int weight = 160lbs;

O_o, units!? That would be absolutely awesome. Is this some c++11 thing? How does that work? Ref? (Google gave nothing)

#16 Cornstalks   Crossbones+   -  Reputation: 6882

Like
4Likes
Like

Posted 04 October 2012 - 02:54 PM


	 int height = 5ft + 9in;
	 int weight = 160lbs;

O_o, units!? That would be absolutely awesome. Is this some c++11 thing? How does that work? Ref? (Google gave nothing)

They are user-defined literals. Note that they should be prefixed with an underscore to be technically right. You have to declare and define the custom literals yourself.
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

#17 Servant of the Lord   Crossbones+   -  Reputation: 15018

Like
0Likes
Like

Posted 04 October 2012 - 03:18 PM

Yep, they are a C++11 feature. Suffixes only, no prefixes at this point. Here's wikipedia's thoughts.
Alas I can't use it yet, since I'm still on MinGW/GCC 4.6, and those (and most of the above C++11 features I mentioned) are on 4.7. Posted Image

@Cornstalks: Thanks for the tips about the underscore! The user-defined literals should've also (better/safer coding) returned a user-defined type, like Length, instead of putting it into a generic int: Length myHeight = (4_feet + 8_inches);

Edited by Servant of the Lord, 04 October 2012 - 03:27 PM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#18 Agbahlok   Members   -  Reputation: 262

Like
0Likes
Like

Posted 04 October 2012 - 03:27 PM

Thanks a lot for all those MUCH useful answers ! I didn't even expect to learn so much when I posted this thread. I know everything I wanted to know and even more. Well, I gave most of you +rep. Also you convinced me to use initializer lists more often. It's just drop in the ocean of knowledge I'd like to have, but, well, that's a step. Thank you.

#19 Slavik81   Members   -  Reputation: 360

Like
3Likes
Like

Posted 04 October 2012 - 04:33 PM


If there is a compiler that does not issue a warning when you put initializers out of order, you should switch to one that does.


FYI Visual c++ 2012 does not issue a warning about this with /wall (and 'language extensions' disabled fwiw). I know gcc does, and I agree that it's a useful warning.

Yeah, msvc is the only compiler I know of that doesn't support that warning. For gcc, clang and intel, the flag is -Wreorder.

You could vote for it if you want Microsoft to add it.

#20 taz0010   Members   -  Reputation: 248

Like
4Likes
Like

Posted 05 October 2012 - 11:40 PM

Most modern compilers will optimize the trivial stuff. So I only stick important things (large items, parent classes, references, ect...) in the initializer list, as I really don't like them. My big issue is that the order items are initlialized in the initializer list is not the same order as they are listed. Which for dependent items can really lead to some hard to track down bugs.


Why is this being voted down? His gripe about the initialiser list order not being the actual initialisation order is perfectly valid. It's intuitive to assume that the variables are going to be initialised in the order that the initialisation code is written - which is exactly the case whenever you initialise something using the equals sign.

Also mentioned in this topic, ordering your members for alignment or caching reasons can potentially break your code if one member was initialised using the value of another. And since headers are used, the potential error will not even be visible in the file where the initialisation code is actually written.

Personally if I have primitive variables that I need to initialise in a specific order, I'm not going to rely on the class definition order to do it, and that means good old fashioned assignment with the = operator.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS