Sign in to follow this  
c_olin

Modern C++ standards/conventions...

Recommended Posts

I've noticed here that a lot of people suggest staying away from conventions that are (or were) considered good in C++. Such as variable prefixes and accessing functions simply returning a member variable, etc. I'm interested if there are any articles on this subject at all. I'd like a good read on the reasons behind these ideas and examples of using it correctly. I understand it is just style, but I would like to read why people feel so strongly on these ideas. It kind of sucks to post code that was perfectly acceptable a couple years ago but get dozens of comments on why you shouldn't do certain things.

Share this post


Link to post
Share on other sites
Variable prefixes (I'm assuming you're referring to hungarian notation) were never good style in C++. They may have been somewhat useful before clever IDEs were widely used, but nowadays there's really no point in using them. Also, they put way too much emphasis on the type of a variable, which, in a language that supports dynamic binding is also not quite what you want.

As for accessor-functions: Having lots of accessor functions in your code generally means that there are too many dependencies between your classes. There's really nothing wrong with accessor functions per se, it's just the way they're used that's bad. Also, accessor functions break encapsulation more than declaring another class a "friend" does.

Share this post


Link to post
Share on other sites
Quote:
Original post by c_olinI understand it is just style, but I would like to read why people feel so strongly on these ideas.


Accessors have gone the way of the singleton, where they are abused. C# with properties and Java with generated class stubs didn't help either. Functional languages have also gained some more main-stream acceptance, and accessors go against that.

Prefixes are again disliked mostly due to abuse that came about through Microsoft's mis-guided version of hungarian notation.

Quote:
It kind of sucks to post code that was perfectly acceptable a couple years ago but get dozens of comments on why you shouldn't do certain things.


Welcome to software development. Your code is actually 50-100 human years old. I don't think any racers would be impressed with steam powered car these days.

And there's nothing wrong with your code - like there's nothing wrong with improving yourself.

Share this post


Link to post
Share on other sites
My only problem is that the majority of the responses are along the lines of "Don't do that" rather than "Here is a better way".

Thats why I'm looking for some sort or article or book on the subject. I have been going by this site:

http://www.possibility.com/Cpp/CppCodingStandard.html

Is that so outdated? If so, what is a more up-to-date one to read up on?

As for variable prefixes, I was more referring to m_variable or mVariable for members. I've seen people get flak left and about this and to me it seems like a perfectly useful convention.

Share this post


Link to post
Share on other sites
I think of the m prefix for member the same way I think of the C prefix for classes - totally redundant.

I often ask people who I think are new to question why they use this convention. Often they blindly copy it from some tutorials of dubious quality found on the internet.

If they have a reason then that is fine - I've always held to my belief that you can do whatever you like in the privacy of your own IDE. But when posting stuff on public forums, I criticize such style much in the same way I would criticize someone who decides that manually handling memory is a better solution to the Standard C++ Library / Boost whatever.

I am more militant about the C prefix than the m prefix, I mostly let the m prefix slide. Often if I post a response to someone using the m prefix I tend to strip it from my source replies.

Share this post


Link to post
Share on other sites
Quote:
Original post by c_olin
My only problem is that the majority of the responses are along the lines of "Don't do that" rather than "Here is a better way".

Thats why I'm looking for some sort or article or book on the subject. I have been going by this site:

http://www.possibility.com/Cpp/CppCodingStandard.html

Is that so outdated? If so, what is a more up-to-date one to read up on?


It's not, but reading through it it's somewhat theoretical.

Just a random example:
XX& operator=(XX& val);

I prefer to put references next to variables, or if not conflicting, in between:
XX & operator=(XX & val);
or
XX &operator=(XX &val);
Reasoning for this has been debated often, but all options are valid. Just try to be consistent.

Another thing I also dislike from that document are comments:
//============================= OPERATORS ====================================

XX&
XX::operator=(const XX&);
{
return *this;

}// =

//============================= OPERATIONS ===================================
//============================= ACESS ===================================
//============================= INQUIRY ===================================
/////////////////////////////// PROTECTED ///////////////////////////////////

/////////////////////////////// PRIVATE ///////////////////////////////////


I mean, it's like a kid with crayons going wild. Yelling at that.

I also completely disagree with Do Work in Open topic, since it makes it impossible to follow RAII. The example given there is C-ish anyway. Calling exit() at that. I'd simply go with:

class Device
{
public:
Device( const std::string & name ) {
// try to open device by name;
if (failed) throw std::exception("Failed to open device");
}
};

Device dev("/dev/random"); // voila, clean, and no need to check for errors



Quote:
As for variable prefixes, I was more referring to m_variable or mVariable for members. I've seen people get flak left and about this and to me it seems like a perfectly useful convention.


Depends on your naming convention. It can be practical, or it can be redundant.


Ultimately, there is no one style. Use what you find ok, but listen to those that disagree. Sometimes they have a point, sometimes their suggestions aren't applicable to your project.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
Often if I post a response to someone using the m prefix I tend to strip it from my source replies.


That's very sneaky...

I'm just curious how you name the arguments in a constructor which simply sets certain member values.


public:
ModernCppClass(int ?, int ?, float?) {
width = ?;
height = ?;
somethingDescriptive = ?;
}

private:
int width;
int height;
float somethingDescriptive;



Obviously the constructor wouldn't be defined in the header. I'm just curious on how you would name the arguments in a similar condition.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-offI often ask people who I think are new to question why they use this convention. Often they blindly copy it from some tutorials of dubious quality found on the internet.


I used it sometimes when doing template heavy classes in order to free some brain CPU cycles for not needing to think of different names.


template < class Start, class End >
struct basic_range
{
basic_range( Start start, End end )
: m_start(start)
, m_end(end)
{}

Start start() const { return m_start; }
End end() const { return m_end; }

Start m_start;
End m_end;
};

typedef basic_range<int, int> IntRange;




Here, names are preserved, and 3 different names are automatically provided to you for the effort of coming up with one.

Template parameters Start and End are self-describing, and this notion is transferred through the entire class. Since with templates you're dealing with concepts, applying tangible names (firstCharacter, lastCharacter) is pointless if you're dealing with ints, for example.

The above approach automatically prevents conflicts between function and template parameters, and comes handy when you need to expose the members (in a fashion similar to iterators).

The above is simply based on observation that lots of templated code is very boiler-plate like with somewhat verbose declaration all carrying simple names.

This paradigm also sits well with certain Boost and SC++L classes, again used in conjunction with templates, where certain names have high chance of conflicting with each other.

Quote:
I'm just curious how you name the arguments in a constructor which simply sets certain member values.


By using initializer lists:
ModernCppClass(int width, int height, float somethingDescriptive ) 
: width( width )
, height( height )
, somethingDescriptive( somethingDescriptive )
{}

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
By using initializer lists:*** Source Snippet Removed ***


I've learned something new. I didn't know that the parameters in the initializer list could be the same name.

What about in a similar case that happens to be in a public function rather than a constructor?

Also, why is it that accessor functions are now often frowned upon? It makes perfect sense to me to leave the implementation completely private and expose everything only with functions.

Share this post


Link to post
Share on other sites
Quote:
Original post by c_olin
Also, why is it that accessor functions are now often frowned upon? It makes perfect sense to me to leave the implementation completely private and expose everything only with functions.


Yes, and by providing accessors, you're exposing implementation. They defeat the purpose of encapsulation.

This is the same thinking that brought about singletons. Globals are bad, so we'll use singletons instead. Now we no longer have globals, and we're completely object oriented.

If your accessors need to do something useful, then provide them. But to simply return a variable, you don't need them. Firstly, why does someone need to know about a variable stored somewhere else, classes should encapsulate what they need to know, and communicate via actions (methods). And if someone does need to know, then you can use a POD struct.

If your setters are doing something extra (like triggering event notifications, doing data validation, affecting classes internal state, then they by definition become more than accessors.

if your getters are doing more than just returning a value (iterators, for example, save memory by being allocated as needed, rather than being a member), then they become more than accessors.

But this:

int getFoo() const { return foo; }
void setFoo(int new_foo) { foo = new_foo; }
is simply pointless. You didn't achieve any encapsulation, you didn't add any new information, and new functionality, you merely increased the code clutter by a factor of 10.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
int getFoo() const { return foo; }
void setFoo(int new_foo) { foo = new_foo; }
is simply pointless. You didn't achieve any encapsulation, you didn't add any new information, and new functionality, you merely increased the code clutter by a factor of 10.

What?!

That, by definition, *IS* encapsulation.

It allows you to change the internal functionality without changing the interface. We strictly enforce it here, and for good reason.

Today, I ended up modifying a few of these. Specifically:

Quote:
void SetLocked(bool flag) { mIsLocked= flag; }
void SetBar(foo f) { mFoo=f; }
had been used for months in our code. Your post would say they are unnecessary. But today, they turned in to:
Quote:
void SetBar(foo f) 
{
if(mIsLocked)
{
mDelayedFoo = f;
return;
}
mDelayedFoo = foo::none;
mFoo = f;
DoSomething(f);
}

void SetLocked(bool flag)
{
mIsLocked= flag;
if(flag==false && mDelayedFoo != foo::none)
{
SetBar(mDelayedFoo);
}
}

This is *EXACTLY* the purpose of encapsulation. It reduced what would have been a multi-hour task of finding everywhere that would have modified the value directly (ewww), and dropped it down to a half-hour of figuring it out, fixing it, and testing a simple change inside the well-used interface.

Share this post


Link to post
Share on other sites
Now I'm cunfused....

both antheus and frob has their point...

@antheus can you elaborate more about get/set method(or what you call getters/setters) being more than accessor method,if possible give some code example on how get/set method become more than accessor method??? what will you do if you what to know an info about a member variable of an object??? so you mean that the member function length() of class string in c++ is useless(or not appropriate)

Share this post


Link to post
Share on other sites
Quote:
Original post by frob
Quote:
Original post by Antheus
int getFoo() const { return foo; }
void setFoo(int new_foo) { foo = new_foo; }
is simply pointless. You didn't achieve any encapsulation, you didn't add any new information, and new functionality, you merely increased the code clutter by a factor of 10.

What?!

That, by definition, *IS* encapsulation.

It allows you to change the internal functionality without changing the interface. We strictly enforce it here, and for good reason.

Today, I ended up modifying a few of these. Specifically:

Quote:
void SetLocked(bool flag) { mIsLocked= flag; }
void SetBar(foo f) { mFoo=f; }


The difference is you didn't really have accessors in the first place, just poorly named functions. Is the purpose of SetLocked() to set a variable called 'locked', making it nothing more than a pointless accessor (as the name suggests), or is it's purpose to provide the functionality of locking access to something? Just because the implementation only needs to mark a flag internally doesn't make it an accessor, really SetLocked() would be better called Lock() or something similar depending on what it's doing (and similar argument for SetBar(), whatever it actually does).

Yes it seems minor, but conceptually it's an important distinction. You don't have accessor functions for x,y,z,w on your vector class, right?

Share this post


Link to post
Share on other sites
So I read that post on getters/setters and it was an informative read. But what if other classes simply need the data? For example a camera class. Would its position/target/up vectors be public? And what about a scene node, surely other classes will need to get their positions and orientations, would their matrices be public aswell?

I see how getters/setters can be reduced (after reading that post). But I am very hesitant to put data that simply needs to be accessed by other classes public. Getters/setters make so much more sense than that (to me).

Am I not thinking about this correctly?

Share this post


Link to post
Share on other sites
Quote:
Original post by c_olin
So I read that post on getters/setters and it was an informative read. But what if other classes simply need the data? For example a camera class. Would its position/target/up vectors be public? And what about a scene node, surely other classes will need to get their positions and orientations, would their matrices be public aswell?


Using getters only is perfectly valid as sometimes internal state needs to be read (how else do you print out a characters stats?). In your case you could provide a getter for the node's transformation matrix but you wouldn't provide a setter (since you don't want someone to be able to set random values in the transformation), you would instead provide functions such as Translate(), Rotate(), etc.

Share this post


Link to post
Share on other sites
Quote:
Original post by c_olin
So I read that post on getters/setters and it was an informative read. But what if other classes simply need the data? For example a camera class. Would its position/target/up vectors be public? And what about a scene node, surely other classes will need to get their positions and orientations, would their matrices be public aswell?

I see how getters/setters can be reduced (after reading that post). But I am very hesitant to put data that simply needs to be accessed by other classes public. Getters/setters make so much more sense than that (to me).

Am I not thinking about this correctly?
It's all about keeping the data, and the methods that operate on that data, in the same class. Providing getters and setters typically seperates the algorithms that use the data from the class that holds it.
The variables usually either should belong in a different class, or the functions operating on them need to belong to the class holding the variables. As with everything though, there are exceptions.

Share this post


Link to post
Share on other sites
Quote:
Original post by joanusdmentia
Quote:
Original post by c_olin
So I read that post on getters/setters and it was an informative read. But what if other classes simply need the data? For example a camera class. Would its position/target/up vectors be public? And what about a scene node, surely other classes will need to get their positions and orientations, would their matrices be public aswell?


Using getters only is perfectly valid as sometimes internal state needs to be read (how else do you print out a characters stats?). In your case you could provide a getter for the node's transformation matrix but you wouldn't provide a setter (since you don't want someone to be able to set random values in the transformation), you would instead provide functions such as Translate(), Rotate(), etc.


Yeah, I definitely see why a setting would not be a good idea in that case. But what about the camera class? I've already run into places where I need to change the FOV or the target from outside the class. Is it a bad idea to have both a getter and a setter for the FOV or the target vector? Should it be public?

Share this post


Link to post
Share on other sites
Quote:
Original post by c_olin

Yeah, I definitely see why a setting would not be a good idea in that case. But what about the camera class? I've already run into places where I need to change the FOV or the target from outside the class. Is it a bad idea to have both a getter and a setter for the FOV or the target vector? Should it be public?


On the camera you definitely don't want data like FOV etc public because:
1. this will lock you down to a single internal representation of a camera
2. you cant manage stuff like "recalculate view matrix when user want to change FOV automatically" without some encapsulement.

Things like this have to decided on a case-by-case basis. If you have POD type (plain old data, like vector etc) you don't want accessors. If you have something where its a gain to hide the internal representation and you have a feeling it might change in the future (this stuff is all down to experience).

If you are unsure, go with accessor methods. it better than having used public data and suddenly need to hook in some extra logic when that data is changed, but as mentioned above, going the old Java route and making everything public will spread out solutions to particular problems and increase dependencies between classes.





Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
Quote:
Original post by rip-offI often ask people who I think are new to question why they use this convention. Often they blindly copy it from some tutorials of dubious quality found on the internet.


I used it sometimes when doing template heavy classes in order to free some brain CPU cycles for not needing to think of different names.


I agree, and remember using something similar in the past when faced with the same situation. I was mainly referring to the "C" prefix with that statement though, I cannot understand why anyone uses that, ever [smile]. Reading it again I can see it doesn't really come across that way though.

Since I've started using Lua a lot, I've adopted my own convention of using underscores to mark private variables.

Quote:

That's very sneaky...


[wink]

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
Since I've started using Lua a lot, I've adopted my own convention of using underscores to mark private variables.


I tend to have similar conventions in OCaml, except that I decorate the local variable instead of the member one:
class foo = object

val mutable bar = 42

method set_bar bar' =
bar <- bar'

method get_bar =
bar

end
Although I don't use accessors much in OCaml anyway.

Share this post


Link to post
Share on other sites
Quote:
Original post by c_olin
My only problem is that the majority of the responses are along the lines of "Don't do that" rather than "Here is a better way".


Whenever I write something like that, it's because the "better way" is implicit. The alternative to using prefixes is, well, not using them, so there's nothing to describe about the "better way".

Share this post


Link to post
Share on other sites
Quote:
Original post by frob
Quote:
Original post by Antheus
int getFoo() const { return foo; }
void setFoo(int new_foo) { foo = new_foo; }
is simply pointless. You didn't achieve any encapsulation, you didn't add any new information, and new functionality, you merely increased the code clutter by a factor of 10.

What?!

That, by definition, *IS* encapsulation.


I'm sorry. That is "encapsulation" in letter, but not in spirit. Writing things this way tends to let programmers feel good about themselves, while giving themselves more work. It does not tend to provide a "hook" for "changing the implementation" that actually gets used, in practice. I know it happened to you. The plural of anecdote is not data.


Quote:
Today, I ended up modifying a few of these. Specifically:

[code]void SetLocked(bool flag) { mIsLocked = flag; }


The point is to get away from the mutator mindset, when you design your interface.


// Aside from the debate about 'm' prefixes, what's the point of "Is" in
// boolean variables? C++ has a *real*, type-safe boolean type. This is really
// a stealth form of Hungarian notation.
void lock() { locked = true; }
void unlock() { locked = false; }


And then it changes to:


void lock() { locked = true; }
void unlock() {
locked = false;
if (DelayedFoo != foo::none) {
SetBar(DelayedFoo);
}
}


The difference is that you aren't thinking in terms of setting some "locked" status value. You're thinking in terms of locking and unlocking.

Of course, you can't always do that. What are your foos and bars exactly?

Share this post


Link to post
Share on other sites
If you ask 3 people about accessors, you get 4 answers.
If you ask 3 people about naming standards, you get a riot.
Don't do it :)

Both accessors and standards are good if you use them right. And they are both bad if you use them wrong. What is right and what is wrong? Nobody else can tell you.

For me, Class names are camel case and start with a capital letter, while variables start with a lower letter, whether they are members or not. For some reason, I want all my typedefs in lowercase and end with "_t", and I write my const variables in lowercase with underscores. Don't ask me why, it probably doesn't even make sense, but that's how I like it.
Other people maybe don't feel comfortable that way. They might be confused, if they don't have their "m_" in front of a member, or if their classes don't have their "C".
Don't force yourself (or others) to something you're not comfortable with. Choose something that you (and your team) are happy with, and adhere to that. Do not let anyone else tell you differently.

Programming languages are meant to be an abstraction over the ugly naked machine code (which, in the end, is only a sequence of numbers) that lets you express your ideas and concepts in a way that is comfortable to your brain, and that helps you to prevent mistakes, and save work. It's a means, not a purpose.

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