Related
I like coding standards. When writing C++ I love coding standards. A good coding standard adds context to the language, making the hard to parse a little bit easier.
There are a few commonly practiced standards that I think everyone is at least a little bit familiar with:
Member variables prefixed with 'm' or 'm_'
Class prefix (generally project specific, ie in Qt all class names are prefixed with 'Q')
Include guard conventions like "take the filename in all caps, replace '.' with '_' "
The rule of three
There are lots of little C++ rules like this. Unfortunately I've never managed to find guidelines like this relating to templates. I think the most popular name for a template argument is 'T', but it's meaningless and unless the template is obvious it can make the code even trickier to read.
Anyway, the core problem I have is that templates are hard to read and I think some convention could be used to make them easier to read. Does anyone know of a widely applied convention that makes templatized code easier to read?
Just adding my grain of salt. I think the two most important libraries in the world of C++ programming are the Standard Template Libraries and the Boost Libraries. I personally try to mostly conform to the kind of notation that is predominant in these libraries. That is, underscore-separated lower-case names for classes, functions, data members, typedefs, enums, etc., and CamelCase (no underscore separation) for template arguments. Typically, you want to also have sensible names for template arguments. A good practice is to give them the name of the concept they should be implementing (e.g. a template argument which should be an iterator that implements ForwardIteratorConcept should be named ForwardIterator).
The conventions that you mentioned ("m" for members and Capital-letter-starting names for classes) is a sort-of pure Object-Oriented Programming convention ("pure" is meant as in: without any other programming paradigms like generic programming or template meta-programming). It is mostly used in Java (or by Java "natives" who are programming C++). I personally don't like it and know few people who do. I'm always a bit annoyed when working within a framework or project that adopts this notation, it de-tones with the standard libraries, boost libraries, and the overall proper usage of namespaces.
My recommendation is to always look at a language's standard libraries for examples of set a coding convention. The result is that your code will read more naturally for the language in which it is written. Basically, write C++ that looks like it could be part of the ISO C++ documents.
For C++, the standard containers, iterators and algorithms have many templates you can use as examples.
As a counter example, using camel case will make your C++ code to read like Java. When you end up using things from the standard library along side your own code, it will look weird.
That said, there are two exceptions to consider. Firstly, if you already have a large code base, follow what's already there: a mix of styles is confusing. Secondly, there are excellent libraries, such as Qt, that do not follow the style of the standard libraries, they are also worthy as examples of coding standards.
* Member variables prefixed with 'm' or 'm_'
Questionable.
* Class prefix (generally project specific, ie in Qt all class names are prefixed with 'Q')
Terrible. Was a necessary practice back in the day.
Big three isn't really a standard either and has pretty much been superceeded as a good practice by the Big Two (because using RAII for pointers negates the necessity of a destructor even when you need Copy ctr and assignment).
At any rate....
You need to differentiate your template parameters from normal code. Thus, you should use a naming convention that you are not using in standard code for template parameters. One good method, used by a good many, is to use CamelCase for template parameters. Another important aspect is, since C++ doesn't enforce concepts at all, to name your parameters after the concept they expect. ForwardIter thus makes a good parameter name for a parameter than should be a forward iterator.
Of course, if you're already using CamelCase for your class names (Java programmers - blech :p) then you should use something else.
When you get into complex instantiations and such then you need to use some method of declaring your template instantiations in multiple lines. When metaprogramming you also often need to split things up into multiple lines and/or multiple types/templates. It's one of those learn as you go things. I like the following method:
template < typename MyParams >
struct my_metafunction
: mpl::if_
<
check // probably wouldn't actually split this one since it's trivial...but as example...
<
MyParams
>
, some_type_expression
, some_other_type_expression
>
{};
There are no "common conventions" for names. Even the conventions you mention aren't as common as you might think. I can't think of anyone using m or m_ prefix for class member data other than a subset of Windows developers. Similarly for prefixing class names.
Conventions of this sort are very project-specific. You agree about them in a project and move on. When you start a new project it's perfectly alright to have new conventions if you so desire. If you lack imagination or confidence to pick your own conventions then buy Herb Sutter and Andrei Alexandrescu's C++ Coding Standards book. In fact, you should really read it because it deals with far more effective conventions than naming conventions. With things that actually matter.
If it at all helps I sometimes see people choosing for template parameters short names that start with a capital letter. E.g., template<class Ch, class Tr>. Look in your compiler's standard library for inspiration.
Take a look at Boost if you want to see their coding convention.
Like the others say, it depends on the project coding style. I like using lowercase letters separated with under score while coding. And for the harmony I use lowercase letters for template parameters too. To distinguish them from the others, I start with underscore and end with "_t".
`
template<typename _encoder_t>
class compression
{
typedef typename _encoder_t::settings settings_t;
...
};
`
For my projects, I usually define a lot of aliases for types like unsigned int, char and double as well as std::string and others.
I also aliased and to &&, or to ||, not to !, etc.
Is this considered bad practice or okay to do?
Defining types to add context within your code is acceptable, and even encouraged. Screwing around with operators will only encourage the next person that has to maintain your code to bring a gun to your house.
Well, consider the newcomers who are accustomed to C++. They will have difficulties maintaining your project.
Mind that there are many possibilities for the more valid aliasing. A good example is complicated nested STL containers.
Example:
typedef int ClientID;
typedef double Price;
typedef map<ClientID, map<Date, Price> > ClientPurchases;
Now, instead of
map<int, map<Date, double> >::iterator it = clientPurchases.find(clientId);
you can write
ClientPurchases::iterator it = clientPurchases.find(clientId);
which seems to be more clear and readable.
If you're only using it for pointlessly renaming language features (as opposed to the example #Vlad gives), then it's the Wrong Thing.
It definitely makes the code less readable - anyone proficient in C++ will see (x ? y : z) and know that it's a ternary conditional operator. Although ORLY x YARLY y NOWAI z KTHX could be the same thing, it will confuse the viewer: "is this YARLY NOWAI the exact same thing as ? :, renamed for the author's convenience, or does it have subtle differences?" If these "aliases" are the same thing as the standard language elements, they will only slow down the next person to maintain your code.
TLDR: Reading code, any code, is hard enough without having to look up your private alternate syntax all the time.
That’s horrible. Don’t do it, please. Write idiomatic C++, not some macro-riddled monstrosity. In general, it’s extremely bad practice to define such macros, except in very specific cases (such as the BOOST_FOREACH macro).
That said, and, or and not are actually already valid aliases for &&, || and ! in C++!
It’s just that Visual Studio only knows them if you first include the standard header <ciso646>. Other compilers don’t need this.
Types are something else. Using typedef to create type aliases depending on context makes sense if it augments the expressiveness of the code. Then it’s encouraged. However, even better would be to create own types instead of aliases. For example, I can’t imagine it ever being beneficial to create an alias for std::string – why not just use std::string directly? (An exception are of course generic data structures and algorithms.)
"and", "or", "not" are OK because they're part of the language, but it's probably better to write C++ in a style that other C++ programmers use, and very few people bother using them. Don't alias them yourself: they're reserved names and it's not valid in general to use reserved names even in the preprocessor. If your compiler doesn't provide them in its default mode (i.e. it's not standard-compliant), you could fake them up with #define, but you may be setting yourself up for trouble in future if you change compiler, or change compiler options.
typedefs for builtin types might make sense in certain circumstances. For example in C99 (but not in C++03), there are extended integer types such as int32_t, which specifies a 32 bit integer, and on a particular system that might be a typedef for int. They come from stdint.h (<cstdint> in C++0x), and if your C++ compiler doesn't provide that as an extension, you can generally hunt down or write a version of it that will work for your system. If you have some purpose in mind for which you might in future want to use a different integer type (on a different system perhaps), then by all means hide the "real" type behind a name that describes the important properties that are the reason you chose that type for the purpose. If you just think "int" is unnecessarily brief, and it should be "integer", then you're not really helping anyone, even yourself, by trying to tweak the language in such a superficial way. It's an extra indirection for no gain, and in the long run you're better off learning C++, than changing C++ to "make more sense" to you.
I can't think of a good reason to use any other name for string, except in a case similar to the extended integer types, where your name will perhaps be a typedef for string on some builds, and wstring on others.
If you're not a native English-speaker, and are trying to "translate" C++ to another language, then I sort of see your point but I don't think it's a good idea. Even other speakers of your language will know C++ better than they know the translations you happen to have picked. But I am a native English speaker, so I don't really know how much difference it makes. Given how many C++ programmers there are in the world who don't translate languages, I suspect it's not a huge deal compared with the fact that all the documentation is in English...
If every C++ developer was familiar with your aliases then why not, but you are with these aliases essentially introducing a new language to whoever needs to maintain your code.
Why add this extra mental step that for the most part does not add any clarity (&& and || are pretty obvious what they are doing for any C/C++ programmer, and any way in C++ you can use the and and or keywords)
I've seen people use a trailing underscore for member variables in classes, for instance in the renowned C++ FAQ Lite.
I think that it's purpose is not to mark variables as members, that's what "m_" is for. It's actual purpose is to make it possible to have an accessor method named like the field, like this:
class Foo {
public:
bar the_bar() { return the_bar_; }
private:
bar the_bar_;
}
Having accessors omit the "get_" part is common in the STL and boost, and I'm trying to develop a coding style as close to these as possible, but I can't really see them using the underscore trick. I wasn't able to find an accessor in STL or boost that would just return a private variable.
I have a few questions I'm hoping you will be able to answer:
Where does this convention come from? Smalltalk? Objective-C? Microsoft? I'm wondering.
Would I use the trailing underscore for all private members or just as a workaround in case I want to name a function like a variable?
Can you point me to STL or boost code that demonstrates trailing underscores for member variables?
Does anybody know what Stroustrup's views on the issue are?
Can you point me to further discussion of the issue?
In C++,
identifiers starting with an underscore, followed by a capital character
identifiers having two consecutive underscores anywhere
identifiers in the global namespace starting with an underscore
are reserved to the implementation. (More about this can be found here.) Rather than trying to remember these rules, many simply do not use identifiers starting with an underscore. That's why the trailing underscore was invented.
However, C++ itself is old, and builds on 40 years of C (both of which never had a single company behind them), and has a standard library that has "grown" over several decades, rather than brought into being in a single act of creation. This makes for the existence of a lot of differing naming conventions. Trailing underscore for privates (or only for private data) is but one, many use other ones (not few among them arguing that, if you need underscores to tell private members from local variables, your code isn't clear enough).
As for getters/setters - they are an abomination, and a sure sign of "quasi classes", which I hate.
I've read The C++ Programming Language and Stroustrup doesn't use any kind of convention for naming members. He never needs to; there is not a single simple accessor/mutator, he has a way of creating very fine object-oriented designs so there's no need to have a method of the same name. He uses structs with public members whenever he needs simple data structures. His methods always seem to be operations. I've also read somewhere that he disencourages the use of names that differ only by one character.
I am personally a big fan of this guideline: http://geosoft.no/development/cppstyle.html
It includes omitting the m_ prefix, using an underscore suffix to indicate private member variables and dropping the horrid, annoying-to-type habit of using underscores instead of space, and other, more detailed and specific suggestions, such as naming bools appropriately(isDone instead of just done) and using getVariable() instead of just variable() to name a few.
Only speaking for myself...
I always use trailing underscore for private data members, regardless if they have accessor functions or not. I don't use m_ mainly because it gets in the way when I mentally spell the variable's name.
As a maintenance developer that likes searchability I'm leaning towards m_ as its more searchable. When you, as me, are maintaining big projects with large classes (don't ask) you sometimes wonder: "Hmmm, who mutates state?". A quick search for m_ can give a hint.
I've also been known to use l_ to indicate local variables but the current project doesn't use that so I'm "clean" these days.
I'm no fan of hungarian notation. C++ has a strong type system, I use that instead.
I'm guessing that utopia would have been to use a leading underscore - this is quite common in Java and C# for members.
However, for C, leading underscores aren't a good idea, so hence I guess the recommendation by the C++ FAQ Lite to go trailing underscore:
All identifiers that begin with an
underscore and either an uppercase
letter or another underscore are
always reserved for any use.
All identifiers that begin with an
underscore are always reserved for use
as identifiers with file scope in both
the ordinary and tag name spaces.
(ISO C99 specification, section 7.1.3)
As far as I remember, it's not Microsoft that pushed the trailing underscore code style for members.
I have read that Stroustrup is pro the trailing underscore.
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 12 years ago.
A discussion recently ended laughing at the bad habits of programmers that have been too exposed to a language when they start programming in another language. The best example would be a Pascal programmer starting to #define begin { and #define end } when starting to write C.
Goal is to try to catch the bad habits of C programmers when they start using C++.
Tell about the big don't that you encountered. One suggestion by answer, please, to try to achieve a kind of best of.
For the ones interested in good habits, have a look at the accepted answer to this question.
Using raw pointers and resources instead of RAII objects.
using char* instead of std::string
using arrays instead of std::vector (or other containers)
not using other STL algorithms or libraries like boost where appropriate
abusing the preprocessor where constants, typedefs or templates would have been better
writing SESE-style (single-entry single exit) code
Declaring all the variables at the top of a function instead of as close as possible to where they are used.
Not using the STL, especially std::string,
and/or
using std::strings and reverting to old c string functions in tight corners.
Writing class definitions that are 2000 lines of code.
Copying and pasting that class definition into 12 different places.
Using switch statements when a simple virtual method would do.
Failing to allocate memory in constructor and deallocate in destructor.
Virtual methods that take optional arguments.
Writing while loops to manipulate char* strings.
Writing giant macro's that are a page in length. (Could have used templates instead).
Adding using's into header files so they can avoid names like std::string in type declarations.
using pointers instead of references
Very experienced developers not understanding casting or even object oriented programming:
I started helping out on a project and one of the senior guys was having a problem with some code that used to work and now didn't.
(Class names have been changed to protect the innocent, and I can't remember the exact names)
He had some C++ code that was listening to incoming message classes and reading them. The way it had worked in the past was that a Message class was passed in and he would interogate a variable on it to find out what type of message it was. He would then C-style cast the Message as another specialised class he'd written that inherited from Message. This new class had functions on it that extracted the data how he wanted it. Now, this had been working for him fine but now was not.
After many hours looking through his code he could not see a problem and I had a look over his shoulder. Immediately I told him that it's not a good idea to C-style cast Message to a derived class which it was not. He disagreed with me and said he'd been doing it for years and if that was wrong then everything he does is wrong because he frequently uses this approach. He was further backed up by a contractor who told me I was wrong. They both argued that this always works and the code hasn't changed so it's not this approach but something else that has broken his code.
I looked a bit further and found the difference. The latest version of the Message class had a virtual function and hadn't previously had any use of virtual. I told the pair of them that there was now a virtual table and functions were being looked up, etc, etc.... and this was causing their problem, etc, etc.... They eventually agreed and I was presented with a comment that I will never forget: "Virtual completely screws up polymorphism and object oriented programming".
I forwarded them a copy of a decorator pattern as an example of how to add a function to an existing class but heard nothing back from them. How they fixed the idea I have no idea.
One word: macros. I am not saying macros have no place at all in C++, but former C programmers tend to use them way too much after they switch to C++.
Using C-style casts.
C++ allows you to independently choose whether to allow casts between unrelated types, and whether to allow changes to const and volatile qualifiers, giving considerable improvements to compile-time type safety compared with C. It also offers completely safe casts at the cost of a runtime check.
C-style casts, unchecked conversions between just about any types, allow whole classes of error that could be easily identified by more restrictive casts. Their syntax also makes them very difficult to search for, if you want to audit buggy code for dubious conversions.
Assuming said programmers have already made the mistake of attempting to learn C++:
Mistakes
Not using STL.
Trying to wrap everything in classes.
Trying to use templates for everything.
Not using Boost. (I know Boost can be a real PITA, and a learning curve, but C++ is just C+ without it. Boost gives C++ some batteries).
Not using smart pointers.
Not using RAII.
Overusing exceptions.
Controversial
Moving to C++. Don't do it.
Try to convert C stdio to iostreams. Iostreams SUX. Don't use it. It's inherently broken. Look here.
Using the following parts of the libstdc++ library:
strings (beyond freeing them for me, go the hell away)
localization (what the hell does this have to do with c++, worse yet, it's awful)
input/output (64 bit file offsets? heard of them?)
Naively believing you can still debug on the command line. Don't use C++ extensively without a code crane (IDE).
Following C++ blogs. C++ blogs carp on about what essentially boils down to metadata and sugar. Beyond a good FAQ, and experience, I've yet to see a useful C++ blog. (Note that's a challenge: I'd love to read a good C++ blog.)
Writing using namespace std because everyone does and then never reflecting on its meaning.
Or knowing what it means but saying "std::cout << "Hello World" << std::endl; looks ugly".
Passing objects with pointers instead of references. Yes, there are still times when you need pointers in C++, but references are safer, so you should use them when you can.
Making everything in a class public. So, data members that should be private aren't.
Not fully understanding the semantics of pointers and references and when to use one or the other. Related to pointers is also the issue of not managing dynamic allocated memory correctly or failing at using "smarter" constructs for that(e.g. smart pointers).
My favourite is the C programmer who writes a single method with multiple, optional, arguments.
Basically, the function would do different things depending on the values and/or nullability of the arguments.
Not using templates when creating algorithms and data structures (example). It makes things either too localized or too generic
I.e. writing
void qsort(MyStruct *begin, size_t length); //too localized
void qsort(void *begin, size_t length,
size_t rec_size, int(compare*)(void*,void*)); //too generic
instead of
template <class RA_Iter>
void qsort(RA_Iter begin, size_t length);
//uses RA_Iter::value_type::operator< for comparison
Well, bad program design transcends languages ( casts, ignoring warnings, unnecessary precompiler magic, unnecessary bit-twiddling, not using the char classification macros ) , and The C language itself doesn't create too many "bad habits" ( Ok, Macros, esp from the stone ages ), and many of the idioms translate directly. But a few that could be considered:
Using a feature just because it's in C++ and so therefore it must be the right way to do something. Some programs just don't need Inheritance, MI, exceptions, RTTI, templates ( great as they are ... the debugging load is steep ), or Virtual class stuff.
Sticking with some code snippet from C, without thinking if C++ has a better way. ( There's a reason you now have class, private, public, const (expanded beyond C89) , static class funcs, references.
Not being familiar with the C++ i/o lib ( its BIG, and you do need to know it) , and mixing C++ i/o and C i/o.
He thinks that C++ is just a little more different language from C. He will continue programming C masked by C++. No advanced use of classes, the structs are considered less powerful than classes, namespace, new headers, templates, nothing of these new elements are used. He will continue declaring integer vars without int, he will not provide functions prototypes. He will use malloc and free, unsafe pointers and preprocessor to define inline functions. This is just a small list ;)
Confused uses of structs vs. classes, overuse of global methods that take object pointers as arguments, and globally-accessible instance pointers, a la:
extern Application* g_pApp;
void RunApplication(Application* app, int flags);
Also (not saying it's totally useless, but still):
const void* buf;
Declaring all the variables at the start of the function itself even if the variable will be used only after 100 lines or so.
Happens especially for local variables declared inside a function.
Solving the problem instead of creating a class-based monstrosity guaranteed to keep you in health insurance and 401K benefits.
Implementing lisp in a single file and doing the design in that.
Writing normal readable functions instead of overriding operators?
Writing in a style which can be understood by the junior programmers which see good practice as "not writing in C++".
Talking to the OS in it's own language.
Not leaving well enough alone, and using C instead.
Would you write something like:
enum XYZ_TYPE {X=1, Y=2, Z=3};
I saw it and the suffix _TYPE confuses me in the enum context. There is a strong prospect that it is because I am not bright.
I would not write it just like that, but it's hardly a make-or-break situation. Roll with the punches and save your frustration for things that really deserve it, like for-case loops. :)
I already have a preferred convention to distinguish types from other identifiers, which is that I use CamelCase with an initial capital for types and lower-case for others. Constants can be all-caps, including enum values.
But "XYZ_TYPE" with any capitalisation is kind of a poor name for an enumeration. I'd use enum Color {RED=1, GREEN=2, BLUE=3};, or enum FuzzyBool {yes=1, no=2, filenotfound=3};, or some such. Not REDGREENBLUE_TYPE.
I think in general if your names are well-chosen then you shouldn't need a _TYPE suffix. If your names aren't well chosen, and to be fair it can be difficult, then maybe you need it to distinguish the type from an object of that type. Maybe. But I prefer to use case.
There is nothing wrong with that suffix as enums are types of their own, they simply are not type safe.
XYZ_TYPE myXYZ = X;
if(myXYZ == 1) { } //This is what I meant by not strongly typed.
C++0x fixes enums so they are strongly typed though.
Just follow whatever your coding standard says about enum type names. In the end it doesn't matter as long as it is consistent with your coding standard, and it is logically sound.
XYZ_TYPE is just another name that follows the C++ variable-naming conventions, though I would prefer to use all capital names for preprocessor definitions.
We'd just call it an XYZ, making it follow our convention of naming types in CamelCase with a leading capital letter. The enumerated values would be eX, eY, and eZ, following out convention of naming values and variables in CamelCase with a leading lowercase letter, and our convention of all enum values starting with e (constants start with k, and there are no other prefixes in general use. We use a very limited set of Light Side Hungarian.)
As with all conventions, your mileage may vary. But suffixing types with _TYPE seems like a beginner's technique that adds little value for the visual clutter it costs.