|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
Situation:
I have a simple struct that, say, holds a color (R, G, and B). I created my own constructors to ease its creation. As a result, I lose the default constructor. I dislike this, but it's easy to solve: I just make my own default constructor. Problem: My own default constructor is considered to be *initializing the variable* (even though it doesn't), whereas the original one does not. Thus, when I declare and use it before initializing it, the compiler no longer warns me. Question: Are there any compiler settings (even compiler specific ones; I am using MSVC++) that state MY default constructor behaves exactly like the regular default constructor? Thanks for your time, Jason P.S. My default constructor could initialize the variable to all 0's, but this has two unwanted effects: 1. It slows down code in which this initialization needn't occur. 2. It potentially hides bugs that would show up if it were left uninitialized as it should be. (This is similar to how MSVC++'s debugger initializes all variables to 0, which is silly, since it should initialize them to randomness -- as will happen in the release build -- to make bugs appear as quickly as possible). |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
Jason Doucette wrote:
> Situation: > I have a simple struct that, say, holds a color (R, G, and B). I > created my own constructors to ease its creation. As a result, I lose > the default constructor. I dislike this, but it's easy to solve: I > just make my own default constructor. > > Problem: > My own default constructor is considered to be *initializing the > variable* (even though it doesn't), whereas the original one does > not. Thus, when I declare and use it before initializing it, the > compiler no longer warns me. That's your choice, isn't it? You've chosen to implement your c-tor (which is supposed to initialise the members) in such a way that does *not* do what it promises to do. So, why are you complaining? It is not a problem, or at least it's very easy to solve, isn't it? > > Question: > Are there any compiler settings (even compiler specific ones; I am > using MSVC++) that state MY default constructor behaves exactly like > the regular default constructor? Not that I know of. > > Thanks for your time, > Jason > > P.S. My default constructor could initialize the variable to all 0's, > but this has two unwanted effects: 1. It slows down code in which > this initialization needn't occur. Can you share the numbers, how much *does* it actually "slow down the code"? > 2. It potentially hides bugs that > would show up if it were left uninitialized as it should be. Written *correctly* it _prevents_ bugs, not hides them. > (This is > similar to how MSVC++'s debugger initializes all variables to 0, which > is silly, since it should initialize them to randomness -- as will > happen in the release build -- to make bugs appear as quickly as > possible). Not similar at all. When in the "debug" build variables are given some values whereas in the "non-debug" they are not, you have a very big problem if your code ever depends on this. When your default c-tor initialises member variables (to 0 or whatever) *always*, there is no randomness, and you can *rely* on the initialisation happening. V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
On Mon, 7 Apr 2008 12:07:03 -0700 (PDT), Jason Doucette
<jdoucette@gmail.com> wrote: >Situation: >I have a simple struct that, say, holds a color (R, G, and B). I >created my own constructors to ease its creation. As a result, I lose >the default constructor. I dislike this, but it's easy to solve: I >just make my own default constructor. > >Problem: >My own default constructor is considered to be *initializing the >variable* (even though it doesn't), whereas the original one does >not. Thus, when I declare and use it before initializing it, the >compiler no longer warns me. > >Question: >Are there any compiler settings (even compiler specific ones; I am >using MSVC++) that state MY default constructor behaves exactly like >the regular default constructor? No. >P.S. My default constructor could initialize the variable to all 0's, >but this has two unwanted effects: 1. It slows down code in which >this initialization needn't occur. Almost certainly by an imperceptible degree. >2. It potentially hides bugs that >would show up if it were left uninitialized as it should be. (This is >similar to how MSVC++'s debugger initializes all variables to 0, which >is silly, since it should initialize them to randomness -- as will >happen in the release build -- to make bugs appear as quickly as >possible). The debugger doesn't do that, and AFAIK, never has. (I've been hearing this for many years, and I still don't know how this rumor got started.) When certain debug options are in effect, the compiler will initialize locals to certain non-zero patterns. -- Doug Harrison Visual C++ MVP |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
On 2008-04-07 15:19:10 -0400, "Victor Bazarov" <v.Abazarov@comAcast.net> said:
> Jason Doucette wrote: >> Question: >> Are there any compiler settings (even compiler specific ones; I am >> using MSVC++) that state MY default constructor behaves exactly like >> the regular default constructor? > > Not that I know of. For the future, though, C++0x will let you do this: struct S { S() = default; S(int); }; with the effect that the compiler will generate that default constructor as if you hadn't declared the other one. -- Pete Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The Standard C++ Library Extensions: a Tutorial and Reference (www.petebecker.com/tr1book) |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
On 7 Apr., 21:07, Jason Doucette <jdouce...@gmail.com> wrote:
> Situation: > I have a simple struct that, say, holds a color (R, G, and B). I > created my own constructors to ease its creation. As a result, I lose > the default constructor. I dislike this, but it's easy to solve: I > just make my own default constructor. > > Problem: > My own default constructor is considered to be *initializing the > variable* (even though it doesn't), whereas the original one does > not. Thus, when I declare and use it before initializing it, the > compiler no longer warns me. > > Question: > Are there any compiler settings (even compiler specific ones; I am > using MSVC++) that state MY default constructor behaves exactly like > the regular default constructor? I don't believe so. > > Thanks for your time, > Jason > > P.S. My default constructor could initialize the variable to all 0's, > but this has two unwanted effects: 1. It slows down code in which > this initialization needn't occur. How likely is this to happen? In correctly written code, most creatíons will have a sensible value available. I doubt that not having a proper initialisation will slow down your program in a measurable way. But if you do have such a beast hanging around, you could do something aka: struct uninitialised_t { }; class rgb { ... rgb( uninitialised_t ) {} ... }; > 2. It potentially hides bugs that > would show up if it were left uninitialized as it should be. Hmmm... having a value of all zeroes does not look that stupid to me. >(This is > similar to how MSVC++'s debugger initializes all variables to 0, which > is silly, since it should initialize them to randomness -- as will > happen in the release build -- to make bugs appear as quickly as > possible). No: randomness is most often not a good solution. But I agree that a value different from 0 might enable you to spot those errors sooner. But why so many uninitialised variables in the first place? My experience is that uninitialised variables always are output parameters and in that case, they are typically filled in the very first statement after their definition. /Peter |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
In article <13dfbe34-adbd-4037-8326-06b330018996
@i36g2000prf.googlegroups.com>, jdoucette@gmail.com says... [ ... ] > P.S. My default constructor could initialize the variable to all 0's, > but this has two unwanted effects: 1. It slows down code in which > this initialization needn't occur. 2. It potentially hides bugs that > would show up if it were left uninitialized as it should be. (This is > similar to how MSVC++'s debugger initializes all variables to 0, which > is silly, since it should initialize them to randomness -- as will > happen in the release build -- to make bugs appear as quickly as > possible). I'd go a step further: instead of leaving the values uninitialized, I'd create a version of the class specifically for debugging: class color { int r_, g_, b_; bool initialized_; public: color() : initialized_(false) {} color(int r, int g, int b) : r_(r), g_(g), b_(b), initialized_(true) {} int red() { assert(initialized_); return r_; } int green() { assert(initialized_); return g_; } int blue() { assert(initialized_); return b_; } operator unsigned long() { assert(initialized_); return r_ << 16 | g_ << 8 | b_; } }; While the compiler no longer warns you about an uninitialized variable, this still gives you a run-time assertion, which is often nearly as useful. -- Later, Jerry. The universe is a figment of its own imagination. |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
> That's your choice, isn't it? You've chosen to implement your c-tor
> (which is supposed to initialise the members) in such a way that does > *not* do what it promises to do. So, why are you complaining? It is > not a problem, or at least it's very easy to solve, isn't it? No, it's not my choice. I do *not want* to make a default constructor myself. I want to keep the original default constructor that does no initialization. But, C++ is forcing me to make my own. > > P.S. My default constructor could initialize the variable to all 0's, > > but this has two unwanted effects: 1. It slows down code in which > > this initialization needn't occur. > > Can you share the numbers, how much *does* it actually "slow down > the code"? I have no numbers. But it may be in code that is run 100's of billions of times. It's probably not that big of a deal in comparison to total program time, so, I'm not concerned. (My thought was, "Why do it if you don't have to?") The second issue was my main concern: > > 2. It potentially hides bugs that > > would show up if it were left uninitialized as it should be. > > Written *correctly* it _prevents_ bugs, not hides them. Forcing everything through a constructor to ensure all objects are initialized should prevent bugs, yes. But, in some cases, I have these color structs that are only initialized *after* they are declared. So, the compiler tells me when I'm being stupid and using them before they are initialized. I lose this warning when I am forced to make my own default constructor, since it thinks I am initializing on declaration, which I'm not. This means I have to make the default constructor initialize it, before I even know what to initialize it to. So, now, when I use it before it's 'really' initialized, I get no warning. So, the only real solution is that I must treat this "somewhat-native style" type as a true class, where whenever it is declared, it must be initialized. It may be cumbersome to do this. I liked thinking about this type as a native data type, not as a class. ![]() > Not similar at all. When in the "debug" build variables are given > some values whereas in the "non-debug" they are not, you have a very > big problem if your code ever depends on this. When your default > c-tor initialises member variables (to 0 or whatever) *always*, there > is no randomness, and you can *rely* on the initialisation happening. Debug builds that zero out everything will hide bugs in code that works properly if all variables are zero'ed out, but doesn't work properly if all variables are set to random values. Unfortunately, when the code is run on customer's machines, they are running in the Release build which is using the random values. That's why Debug should forcibly randomize all unset values to force bugs to appear, and force the programmer to make sure his code is legitimate. (Note that I am talking about native data types.) Jason |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
> >P.S. My default constructor could initialize the variable to all 0's,
> >but this has two unwanted effects: 1. It slows down code in which > >this initialization needn't occur. > > Almost certainly by an imperceptible degree. Agreed. > >2. It potentially hides bugs that > >would show up if it were left uninitialized as it should be. (This is > >similar to how MSVC++'s debugger initializes all variables to 0, which > >is silly, since it should initialize them to randomness -- as will > >happen in the release build -- to make bugs appear as quickly as > >possible). > > The debugger doesn't do that, and AFAIK, never has. (I've been hearing this > for many years, and I still don't know how this rumor got started.) When > certain debug options are in effect, the compiler will initialize locals to > certain non-zero patterns. You are quite right. MSVC++ sets them all to C's in hex, so you can easily see that they are uninitialized in the debugger window. I already knew this, as I tested it with a function I made to show the bits of any data type, so I don't know why I keep thinking they are set to 0. Jason |
|
|
|
#9 |
|
Messages: n/a
Hébergeur: |
> For the future, though, C++0x will let you do this:
> > struct S > { > S() = default; > S(int); > }; > > with the effect that the compiler will generate that default > constructor as if you hadn't declared the other one. Wow, Pete, that's cool. C++0x is the planned new C++ standard, so, I guess I'm not the only one who wants this functionality. Jason |
|
|
|
#10 |
|
Messages: n/a
Hébergeur: |
Jason Doucette wrote:
>>> P.S. My default constructor could initialize the variable to all 0's, >>> but this has two unwanted effects: 1. It slows down code in which >>> this initialization needn't occur. >> Almost certainly by an imperceptible degree. > > Agreed. > > >>> 2. It potentially hides bugs that >>> would show up if it were left uninitialized as it should be. (This is >>> similar to how MSVC++'s debugger initializes all variables to 0, which >>> is silly, since it should initialize them to randomness -- as will >>> happen in the release build -- to make bugs appear as quickly as >>> possible). >> The debugger doesn't do that, and AFAIK, never has. (I've been hearing this >> for many years, and I still don't know how this rumor got started.) When >> certain debug options are in effect, the compiler will initialize locals to >> certain non-zero patterns. > > You are quite right. MSVC++ sets them all to C's in hex, so you can > easily see that they are uninitialized in the debugger window. I > already knew this, as I tested it with a function I made to show the > bits of any data type, so I don't know why I keep thinking they are > set to 0. The reason that MSVC sets them to all 0xcc is not for easy visibility (though that's a nice side-benefit). It's because 0xcc is the INT3 opcode in x86, which breaks to the debugger. |
|
|
|
#11 |
|
Messages: n/a
Hébergeur: |
> How likely is this to happen? In correctly written code, most
> creatíons will have a sensible value available. I doubt that not > having a proper initialisation will slow down your program in a > measurable way. The slow down is likely imperceivable, but my thought was, why initialize a variable twice when it only has to be initialized once? > But if you do have such a beast hanging around, you could do something > aka: > struct uninitialised_t > { > }; > > class rgb > { > ... > rgb( uninitialised_t ) {} > ... > }; Thanks for the tip. The issue was just that I enjoyed the compiler letting me know when I'd use a variable before it was initialized: int i; int a = i + 5; It's not a big deal, but it s catch a few bugs. Now, if all int's are forced to run my own default constructor that sets them to 0, then the above bug is not caught (unless all code that declares int's *wants* them to be init'ed to 0.) > No: randomness is most often not a good solution. But I agree that a > value different from 0 might enable you to spot those errors sooner. > But why so many uninitialised variables in the first place? My > experience is that uninitialised variables always are output > parameters and in that case, they are typically filled in the very > first statement after their definition. I don't have many at all. I declare variables right where they are used, and thus they are initialized on the spot. Certain unique algorithms prevent this, but not often. I'm curious, why is randomness most often not a good solution? Jason |
|
|
|
#12 |
|
Messages: n/a
Hébergeur: |
> I'd go a step further: instead of leaving the values uninitialized, I'd
> create a version of the class specifically for debugging: Thanks for the tip, Jerry! Jason |
|
|
|
#13 |
|
Messages: n/a
Hébergeur: |
> The reason that MSVC sets them to all 0xcc is not for easy visibility
> (though that's a nice side-benefit). It's because 0xcc is the INT3 > opcode in x86, which breaks to the debugger. Ah! Thanks! ![]() Jason |
|
|
|
#14 |
|
Messages: n/a
Hébergeur: |
In article <0f38d01d-718f-495e-b5f0-da59949868b1@w5g2000prd.googlegroups.com>,
Jason Doucette <jdoucette@gmail.com> wrote: >Debug builds that zero out everything will hide bugs in code that >works properly if all variables are zero'ed out, but doesn't work >properly if all variables are set to random values. Unfortunately, >when the code is run on customer's machines, they are running in the >Release build which is using the random values. That's why Debug >should forcibly randomize all unset values to force bugs to appear, >and force the programmer to make sure his code is legitimate. (Note >that I am talking about native data types.) Should do this? Maybe-- such a thing being unavoidable would merely annoy those people that can write good code from day 1. Will it do it? Very darn unlikely. The current default behavior of *optional* filling to fixed values is probably going to be as good as you get out of the box. If you want to check that variables are initialized before use, there are a few options: (1) ramp warning level to 4, and the compiler will check most local variables for use w/o initialization. (2) For classes, add in a constructor in debug builds (only) that checks for initialization. (3) Pay $$$ for a program like Boundschecker that'll make a super-special debug build that does runtime checks for uninitialized variables. (If building for linux, Valgrind is supposed to be able to do this at a much reduced price.) (4) Run your program thru static code checkers, like Coverity, that'll do an amazing job of finding codepaths under which local variables aren't initialized. (Far better than warning level 4). Short summary of things: there's a few ways you can try and find problems like the above for free, and several ways you can spend $$$ and find them faster. As lots of people have mentioned, your insistence on shaving a few ms in release builds is probably hurting you. You can very easily write some code that does a bunch of checks in debug, and goes away in release builds. Nathan Mates -- <*> Nathan Mates - personal webpage http://www.visi.com/~nathan/ # Programmer at Pandemic Studios -- http://www.pandemicstudios.com/ # NOT speaking for Pandemic Studios. "Care not what the neighbors # think. What are the facts, and to how many decimal places?" -R.A. Heinlein |
|
|
|
#15 |
|
Messages: n/a
Hébergeur: |
Jason Doucette wrote:
> No, it's not my choice. I do *not want* to make a default constructor > myself. I want to keep the original default constructor that does no > initialization. But, C++ is forcing me to make my own. You can write a do-nothing constructor, but even that will be heavier than not having a constructor at all: struct C { C() { } ... This is the most lightweight solution you can do in C++ if you already have another constructor. Of course the compiler might add some implicit function calls to it. However, if your structure only contains POD types, they will remain uninitialized. There's a good chance the compiler can inline this for you, and remove the empty body. Another solution to consider: simply don't write your own constructor at all. Create a static function, or a non-member function to initialize your data. Example: struct Color { int r, g, b; static Color Create(int ar, int ag, int ab) { Color c; c.r = ar; c.g = ag; c.b = ab; return c; } }; This has to perform two assignment operations for each member, though. If performance is really so important for you, you might want to use a less convenient method: inline void InitColor(Color& c, int ar, int ag, int ab) { c.r = ar; c.g = ag; c.b = ab; } The compiler will likely inline this for you in release builds. And there's always a possibility of using a macro (ouch!). Otherwise my tip would be to avoid early optimizations, and optimize only after doing some benchmarking. Did you know that calling malloc just once can be a thousand times slower than initializing those integers with 0? There is a possibility that you're trying to optimize something that's not likely to be anywhere near the bottleneck. Tom |
|
|
|
#16 |
|
Messages: n/a
Hébergeur: |
"Jason Doucette" wrote:
> Debug builds that zero out everything will hide bugs in code > that works properly if all variables are zero'ed out, but > doesn't work properly if all variables are set to random values. > Unfortunately, when the code is run on customer's machines, they > are running in the Release build which is using the random > values. That's why Debug should forcibly randomize all unset > values to force bugs to appear, and force the programmer to make > sure his code is legitimate. (Note that I am talking about > native data types.) But debug build does exactly that. I don't know why you think that debug build zeroes out "everything". Exactly the opposite is true: debug build will initialize everyhting with non-zero values by default in order to _avoid_ accidental zeros. "WFC Technical Note 006 - Funny Memory Values" http://www.samblackburn.com/wfc/technotes/WTN006.htm Alex |
|
|
|
#17 |
|
Messages: n/a
Hébergeur: |
Alex Blekhman wrote:
> "Jason Doucette" wrote: >> Debug builds that zero out everything will hide bugs in code >> that works properly if all variables are zero'ed out, but >> doesn't work properly if all variables are set to random values. >> Unfortunately, when the code is run on customer's machines, they >> are running in the Release build which is using the random >> values. That's why Debug should forcibly randomize all unset >> values to force bugs to appear, and force the programmer to make >> sure his code is legitimate. (Note that I am talking about >> native data types.) > > But debug build does exactly that. I don't know why you think that Well, except for the random part. The value the debug build uses is fixed, but carefully chosen so it isn't a valid pointer, etc. > debug build zeroes out "everything". Exactly the opposite is true: > debug build will initialize everyhting with non-zero values by > default in order to _avoid_ accidental zeros. > > "WFC Technical Note 006 - Funny Memory Values" > http://www.samblackburn.com/wfc/technotes/WTN006.htm > > Alex |
|
|
|
#18 |
|
Messages: n/a
Hébergeur: |
> Another solution to consider: simply don't write your own constructor
> at all. Create a static function, or a non-member function to > initialize your data. Example: > > struct Color > { > int r, g, b; > static Color Create(int ar, int ag, int ab) > { > Color c; > c.r = ar; > c.g = ag; > c.b = ab; > return c; > } > }; > > This has to perform two assignment operations for each member, though. > If performance is really so important for you, you might want to use a > less convenient method: > > inline void InitColor(Color& c, int ar, int ag, int ab) > { > c.r = ar; > c.g = ag; > c.b = ab; > } > > The compiler will likely inline this for you in release builds. And > there's always a possibility of using a macro (ouch!). The optimizer should generate the same code for both versions, no need to use the clunkier one (and in fact, the first one is necessary for const-correctness). This is the Named Return Value Optimization (NVRO). |
|
|
|
#19 |
|
Messages: n/a
Hébergeur: |
red floyd wrote:
> Jason Doucette wrote: >>>> P.S. My default constructor could initialize the variable to all >>>> 0's, but this has two unwanted effects: 1. It slows down code in >>>> which this initialization needn't occur. >>> Almost certainly by an imperceptible degree. >> >> Agreed. >> >> >>>> 2. It potentially hides bugs that >>>> would show up if it were left uninitialized as it should be. (This is >>>> similar to how MSVC++'s debugger initializes all >>>> variables to 0, which is silly, since it should initialize them to >>>> randomness -- as will happen in the release build -- to make bugs >>>> appear as quickly as possible). >>> The debugger doesn't do that, and AFAIK, never has. (I've been >>> hearing this for many years, and I still don't know how this rumor >>> got started.) When certain debug options are in effect, the >>> compiler will initialize locals to certain non-zero patterns. >> >> You are quite right. MSVC++ sets them all to C's in hex, so you can >> easily see that they are uninitialized in the debugger window. I >> already knew this, as I tested it with a function I made to show the >> bits of any data type, so I don't know why I keep thinking they are >> set to 0. > > The reason that MSVC sets them to all 0xcc is not for easy visibility > (though that's a nice side-benefit). It's because 0xcc is the INT3 > opcode in x86, which breaks to the debugger. As well as being an invalid pointer (it's in the top 1GB of address space which is reserved for the kernel, attempts to access it from user-mode will cause an access violation). |
|
|
|
#20 |
|
Messages: n/a
Hébergeur: |
> >Debug builds that zero out everything will hide bugs in code that
> >works properly if all variables are zero'ed out, but doesn't work > >properly if all variables are set to random values. Unfortunately, > >when the code is run on customer's machines, they are running in the > >Release build which is using the random values. That's why Debug > >should forcibly randomize all unset values to force bugs to appear, > >and force the programmer to make sure his code is legitimate. (Note > >that I am talking about native data types.) > > Should do this? Maybe-- such a thing being unavoidable would merely > annoy those people that can write good code from day 1. Will it do it? > Very darn unlikely. The current default behavior of *optional* > filling to fixed values is probably going to be as good as you get out > of the box. True, the MSVC++ compiler already fills them with C's, so that'll catch most issues. And the MSVC++ compiler's run time checker stops the code dead as soon as you access it, so that catches ALL issues. (Keep in mind I wrote the above while still under the false impression that it just 0's them out, and the run-time checker doesn't halt on use of uninitialized variables.) > If you want to check that variables are initialized before use, > there are a few options: (1) ramp warning level to 4, and the compiler > will check most local variables for use w/o initialization. That's the first thing I do for any project! (It appears MSVC++IDE remembers this for subsequent projects, or perhaps this is its default, which is great!) > (2) For > classes, add in a constructor in debug builds (only) that checks for > initialization. Good tip. However, in *my* particular case, my color struct is more of a native data type than a class. So, it's used everywhere, and such checks would really, really slow down the Debug builds. (Imagine having a Debug check on each initialization and use of "int". This would be beyond reason for such a type.) I *agree* that this is a good tip for most classes, just not native data types. For them, having the compiler warn about use before initialization is more than fine, which is exactly the thing I'm griping about losing when C++ forces me to create my own default constructor. > (3) Pay $$$ for a program like Boundschecker that'll > make a super-special debug build that does runtime checks for > uninitialized variables. (If building for linux, Valgrind is supposed > to be able to do this at a much reduced price.) MSVC++ has this covered, so I'm all set. > (4) Run your program > thru static code checkers, like Coverity, that'll do an amazing job of > finding codepaths under which local variables aren't initialized. (Far > better than warning level 4). I've heard of these. Amazing programs... Have you had experience with them? > Short summary of things: there's a few ways you can try and find > problems like the above for free, and several ways you can spend $$$ > and find them faster. As lots of people have mentioned, your > insistence on shaving a few ms in release builds is probably hurting > you. You can very easily write some code that does a bunch of checks > in debug, and goes away in release builds. There's a misunderstanding that I'm producing bad code to shave off ms in Release builds. I know of, and employ, many Debug build checks... assert() calls being the most numerous, but I even have some of my own in-depth methods for catching even more things. Trust me, I am not trying to save ms of time. I am trying to produce robust code. The fact that I lose the default constructor, and thus lose the compiler's warning of using a variable before being initialized (both at compile time and at run time), is not a good thing. This allows bugs to creep in. This is what my post is all about. Luckily, in the new C++ standard, my desire of keeping the default constructor is something I can do. I hope the MSVC++ compiler implements this feature soon. ![]() Thanks for your time, Nathan. Jason |
|
|
|
#21 |
|
Messages: n/a
Hébergeur: |
On Apr 8, 3:04 pm, red floyd <no.s...@here.dude> wrote:
> Jason Doucette wrote: > >>> P.S. My default constructor could initialize the variable to all 0's, > >>> but this has two unwanted effects: 1. It slows down code in which > >>> this initialization needn't occur. > >> Almost certainly by an imperceptible degree. > > > Agreed. > > >>> 2. It potentially hides bugs that > >>> would show up if it were left uninitialized as it should be. (This is > >>> similar to how MSVC++'s debugger initializes all variables to 0, which > >>> is silly, since it should initialize them to randomness -- as will > >>> happen in the release build -- to make bugs appear as quickly as > >>> possible). > >> The debugger doesn't do that, and AFAIK, never has. (I've been hearing this > >> for many years, and I still don't know how this rumor got started.) When > >> certain debug options are in effect, the compiler will initialize locals to > >> certain non-zero patterns. > > > You are quite right. MSVC++ sets them all to C's in hex, so you can > > easily see that they are uninitialized in the debugger window. I > > already knew this, as I tested it with a function I made to show the > > bits of any data type, so I don't know why I keep thinking they are > > set to 0. > > The reason that MSVC sets them to all 0xcc is not for easy visibility > (though that's a nice side-benefit). It's because 0xcc is the INT3 > opcode in x86, which breaks to the debugger. Since this is usually stack or heap memory, why would INT 3 be significant? It's not likely to be executed. Deleted memory is set to 0xdd in memory and I've also seen 0xcd used for other states. Here's a link: http://www.docsultant.com/site2/arti...bug_codes.html -- Paul |
|
|
|
#22 |
|
Messages: n/a
Hébergeur: |
> You can write a do-nothing constructor, but even that will be heavier
> than not having a constructor at all: > > struct C > { > C() { } > ... This is what I am doing. (I either have to do this, or make my color struct an aggregate again by removing all my convenient non-default constructors that I made.) Why is this heavier? In the final compilation, shouldn't this produce zero CPU instructions? > This is the most lightweight solution you can do in C++ if you already > have another constructor. Of course the compiler might add some implicit > function calls to it. However, if your structure only contains POD > types, they will remain uninitialized. There's a good chance the > compiler can inline this for you, and remove the empty body. All defined functions inside of a class body are inlined by default, even without the "inline" specifier. (The C++ standard states so, AFAIK, it's not just a MSVC++ addition.) > Another solution to consider: simply don't write your own constructor at > all. Create a static function, or a non-member function to initialize > your data. Example: > > struct Color > { > int r, g, b; > static Color Create(int ar, int ag, int ab) > { > Color c; > c.r = ar; > c.g = ag; > c.b = ab; > return c; > } > }; > > This has to perform two assignment operations for each member, though. Nice tip. Another downfall is that it wouldn't be able to be used in initializing an array of Color, since you'd have to manually call this for each element, rather than calling the constructor right in the array declaration. > If performance is really so important for you, you might want to use a > less convenient method: > > inline void InitColor(Color& c, int ar, int ag, int ab) > { > c.r = ar; > c.g = ag; > c.b = ab; > } > > The compiler will likely inline this for you in release builds. And > there's always a possibility of using a macro (ouch!). Ha ha Performance isn't that important. I just want robust code,and want my compiler's warnings to be intact. > Otherwise my tip would be to avoid early optimizations, and optimize > only after doing some benchmarking. Did you know that calling malloc > just once can be a thousand times slower than initializing those > integers with 0? There is a possibility that you're trying to optimize > something that's not likely to be anywhere near the bottleneck. I agree 100%. Again, I am not concerned with optimization at this time. I am concerned only with robust code. (I wish I had never mentioned making my own constructor initialize the fields to 0 would have the downfall of being slow.) My concern is simply that I want the compiler's warnings for when I use "Color" before initializing it. With its default constructor, I get those warnings. With my default constructor, I don't (since it assumes I'm actually initializing it, of course.) Thanks for your time, Tom Jason |
|
|
|
#23 |
|
Messages: n/a
Hébergeur: |
> But debug build does exactly that. I don't know why you think that
> debug build zeroes out "everything". Exactly the opposite is true: > debug build will initialize everything with non-zero values by > default in order to _avoid_ accidental zeros. Because I think I've heard it a million times, and it's sunken in, even though I have direct evidence of my MSVC++ compiler filling all uninitialized values with C's. Silly me. So, MSVC++ does just what I want, except it doesn't randomize them, but it doesn't need to, since the run-time checker will stop the program anyway, so any inadvertent access will be caught. And by having all C's, instead of randomness, you can easily detect these variables in the Watch window. So, all's well! > "WFC Technical Note 006 - Funny Memory Values"http://www.samblackburn.com/wfc/technotes/WTN006.htm Yup! ![]() Thanks for your time, Alex Jason |