Modern C++ standards/conventions...

Started by
49 comments, last by Leo_E_49 16 years, 2 months ago
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.
Advertisement
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.
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.
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.
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.
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.
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.

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 ){}
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.
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.

This topic is closed to new replies.

Advertisement