Related
C++ style vs. performance - is using C-style things, that are faster the some C++ equivalents, that bad practice ? For example:
Don't use atoi(), itoa(), atol(), etc. ! Use std::stringstream <- probably sometimes it's better, but always? What's so bad using the C functions? Yep, C-style, not C++, but whatever? This is C++, we're looking for performance all the time..
Never use raw pointers, use smart pointers instead - OK, they're really useful, everyone knows that, I know that, I use the all the time and I know how much better they're that raw pointers, but sometimes it's completely safe to use raw pointers.. Why not? "Not C++ style? <- is this enough?
Don't use bitwise operations - too C-style? WTH? Why not, when you're sure what you're doing? For example - don't do bitwise exchange of variables ( a ^= b; b ^= a; a ^= b; ) - use standard 3-step exchange. Don't use left-shift for multiplying by two. Etc, etc.. (OK, that's not C++ style vs. C-style, but still "not good practice" )
And finally, the most expensive - "Don't use enum-s to return codes, it's too C-style, use exceptions for different errors" ? Why? OK, when we're talking about error handling on deep levels - OK, but why always? What's so wrong with this, for example - when we're talking about a function, that returns different error codes and when the error handling will be implemented only in the function, that calls the first one? I mean - no need to pass the error codes on a upper level. Exceptions are rather slow and they're exceptions for exceptional situations, not for .. beauty.
etc., etc., etc.
Okay, I know that good coding style is very, very important <- the code should be easy to read and understand. I know that there's no need from micro optimizations, as the modern compilers are very smart and Compiler optimizations are very powerful. But I also know how expensive is the exceptions handling, how (some) smart_pointers are implemented, and that there's no need from smart_ptr all the time.. I know that, for example, atoi is not that "safe" as std::stringstream is, but still.. What about performance?
EDIT: I'm not talking about some really hard things, that are only C-style specific. I mean - don't wonder to use function pointers or virtual methods and these kind of stuff, that a C++ programmer may not know, if never used such things (while C programmers do this all the time). I'm talking about some more common and easy things, such as in the examples.
In general, the thing you're missing is that the C way often isn't faster. It just looks more like a hack, and people often think hacks are faster.
Never use raw pointers, use smart pointers instead - OK, they're really useful, everyone knows that, I know that, I use the all the time and I know how much better they're that raw pointers, but sometimes it's completely safe to use raw pointers.. Why not?
Let's turn the question on its head. Sometimes it's safe to use raw pointers. Is that alone a reason to use them? Is there anything about raw pointers that is actually superior to smart pointers? It depends. Some smart pointer types are slower than raw pointers. Others aren't. What is the performance rationale for using a raw pointer over a std::unique_ptr or a boost::scoped_ptr? Neither of them have any overhead, they just provide safer semantics.
This isn't to say that you should never use raw pointers. Just that you shouldn't do it just because you think you need performance, or just because "it seems safe". Do it when you need to represent something that smart pointers can't. As a rule of thumb, use pointers to point to things, and smart pointers to take ownership of things. But it's a rule of thumb, not a universal rule. Use whichever fits the task at hand. But don't blindly assume that raw pointers will be faster. And when you use smart pointers, be sure you are familiar with them all. Too many people just use shared_ptr for everything, and that is just awful, both in terms of performance and the very vague shared ownership semantics you end up applying to everything.
Don't use bitwise operations - too C-style? WTH? Why not, when you're sure what you're doing? For example - don't do bitwise exchange of variables ( a ^= b; b ^= a; a ^= b; ) - use standard 3-step exchange. Don't use left-shift for multiplying by two. Etc, etc.. (OK, that's not C++ style vs. C-style, but still "not good practice" )
That one is correct. And the reason is "it's faster". Bitwise exchange is problematic in many ways:
it is slower on a modern CPU
it is more subtle and easier to get wrong
it works with a very limited set of types
And when multiplying by two, multiply by two. The compiler knows about this trick, and will apply it if it is faster. And once again, shifting has many of the same problems. It may, in this case, be faster (which is why the compiler will do it for you), but it is still easier to get wrong, and it works with a limited set of types. In paticular, it might compile fine with types that you think it is safe to do this trick with... And then blow up in practice. In particular, bit shifting on negative values is a minefield. Let the compiler navigate it for you.
Incidentally, this has nothing to do with "C style". The exact same advice applies in C. In C, a regular swap is still faster than the bitwise hack, and bitshifting instead of a multiply will still be done by the compiler if it is valid and if it is faster.
But as a programmer, you should use bitwise operations for one thing only: to do bitwise manipulation of integers. You've already got a multiplication operator, so use that when you want to multiply. And you've also got a std::swap function. Use that if you want to swap two values. One of the most important tricks when optimizing is, perhaps surprisingly, to write readable, meaningful code. That allows your compiler to understand the code and optimize it. std::swap can be specialized to do the most efficient exchange for the particular type it's used on. And the compiler knows several ways to implement multiplication, and will pick the fastest one depending on circumstance... If you tell it to. If you tell it to bit shift instead, you're just misleading it. Tell it to multiply, and it will give you the fastest multiply it has.
And finally, the most expensive - "Don't use enum-s to return codes, it's too C-style, use exceptions for different errors" ?
Depends on who you ask. Most C++ programmers I know of find room for both. But keep in mind that one unfortunate thing about return codes is that they're easily ignored. If that is unacceptable, then perhaps you should prefer an exception in this case. Another point is that RAII works better together with exceptions, and a C++ programmer should definitely use RAII wherever possible. Unfortunately, because constructors can't return error codes, exceptions are often the only way to indicate errors.
but still.. What about performance?
What about it? Any decent C programmer would be happy to tell you not to optimize prematurely.
Your CPU can execute perhaps 8 billion instructions per second. If you make two calls to a std::stringstream in that second, is that going to make a measurable dent in the budget?
You can't predict performance. You can't make up a coding guideline that will result in fast code. Even if you never throw a single exception, and never ever use stringstream, your code still won't automatically be fast. If you try to optimize while you write the code, then you're going to spend 90% of the effort optimizing the 90% of the code that is hardly ever executed. In order to get a measurable improvement, you need to focus on the 10% of the code that make up 95% of the execution time. Trying to make everything fast just results in a lot of wasted time with little to show for it, and a much uglier code base.
I'd advise against atoi, and atol as a rule, but not just on style grounds. They make it essentially impossible to detect input errors. While a stringstream can do the same job, strtol (for one example) is what I'd usually advise as the direct replacement.
I'm not sure who's giving that advice. Use smart pointers when they're helpful, but when they're not, there's nothing wrong with using a raw pointer.
I really have no idea who thinks it's "not good practice" to use bitwise operators in C++. Unless there were some specific conditions attached to that advice, I'd say it was just plain wrong.
This one depends heavily on where you draw the line between an exceptional input, and (for example) an input that's expected, but not usable. Generally speaking, if you're accepting input direct from the user, you can't (and shouldn't) classify anything as truly exceptional. The main good point of exceptions (even in a situation like this) is ensuring that errors aren't just ignored. OTOH, I don't think that's always the sole criterion, so you can't say it's the right way to handle every situation.
All in all, it sounds to me like you've gotten some advice that's dogmatic to the point of ignoring reality. It's probably best ignored or at least viewed as one rather extreme position about how C++ could be written, not necessarily how it always (or ever, necessarily) should be written.
Adding to #Jerry Coffin's answer, which I think is extremely useful, I would like to present some subjective observations.
The thing is that programmers tend to get fancy. That is, most of us really like writing fancy code just for the sake of it. This is perfectly fine as long as you are doing the project on your own. Remember a good software is the one whose binary code works as expected and not the one whose source code is clean. However when it comes to larger projects which are developed and maintained by lots of people, it is economically better to write simpler code so that no one from the team loses time to understand what you meant. Even at the cost of runtime(naturally minor cost). That's why many people, including myself, would discourage using the xor trick instead of assignment(you may be surprised but there are extremely many programmers out there that haven't heard of the xor trick). The xor trick works only for integers anyway, and the traditional way of swapping integers is very fast anyway, so using the xor trick is just being fancy.
using itoa, atoi etc instead of streams is faster. Yes, it is. But how much faster? Not much. Unless most of your program does only conversions from text to string and vice versa you won't notice the difference. Why do people use itoa, atoi etc? Well, some of them do, because they are unaware of the c++ alternative. Another group does because it's just one LOC. For the former group - shame on you, for the latter - why not boost::lexical_cast?
exceptions... ah ... yeah, they can be slower than return codes but in most cases not really. Return codes can contain information, which is not an error. Exceptions should be used to report severe errors, ones which cannot be ignored. Some people forget about this and use exceptions for simulating some weird signal/slot mechanisms (believe me, I have seen it, yuck). My personal opinion is that there is nothing wrong using return codes, but severe errors should be reported with exceptions, unless the profiler has shown that refraining from them would considerably boost the performance
raw pointers - My own opinion is this: never use smart pointers when it's not about ownership. Always use smart pointers when it's about ownership. Naturally with some exceptions.
bit-shifting instead of multiplication by powers of two. This, I believe, is a classic example of premature optimization. x << 3; I bet at least 25% of your co-workers will need some time before they will understand/realize this means x * 8; Obfuscated (at least for 25%) code for which exact reasons? Again, if the profiler tells you this is the bottleneck (which I doubt will be the case for extremely rare cases), then green light, go ahead and do it (leaving a comment that in fact this means x * 8)
To sum it up. A good professional acknowledges the "good styles", understands why and when they are good, and rightfully makes exceptions because he knows what he's doing. Average/bad professionals are categorized into 2 types: first type doesn't acknowledge good style, doesn't even understand what and why it is. fire them. The other type treats the style as a dogma, which is not always good.
What's a best practice ? Wikipedia's words are better than mine would be :
A best practice is a technique,
method, process, activity, incentive,
or reward which conventional wisdom
regards as more effective at
delivering a particular outcome than
any other technique, method, process,
etc. when applied to a particular
condition or circumstance.
[...]
A given best practice is only
applicable to particular condition or
circumstance and may have to be
modified or adapted for similar
circumstances. In addition, a "best"
practice can evolve to become better
as improvements are discovered.
I believe there is no such thing as universal truth in programming : if you think that something is a better fit in your situation than a so called "best practice", then do what you believe is right, but know perfectly why you do (ie: prove it with numbers).
Functions with mutable char* arguments are bad in C++ because it's too difficult to manually handle their memory, since we have an alternatives. They aren't generic, we can't easily switch from char to wchar_t as basic_string allows. Also lexical_cast is more straight replacement for atoi, itoa.
If you don't really need smartness of a smart pointer - don't use it.
To swap use swap. Use bitwise operations only for bitwise operations - checking/setting/inverting flags, etc.
Exceptions are fast. They allow removing error checking condition branches, so if they really "never happen" - they increase performance.
Multiplication by bitshifting doesn't improve performance in C, the compiler will do that for you. Just be sure to multiply or divide by 2^n values for performance.
Bitfield swapping is also something that'll probably just confuse your compiler.
I'm not very experienced with string handling in C++, but from from what I know, it's hard to believe it's more flexible than scanf and printf.
Also, these "you should never" statements, I generally regard them as recommendations.
All of your questions are a-priori. What I mean is you are asking them in the abstract, not in the context of any specific program whose performance is your concern.
That's like trying to swim without being in water.
If you do tuning on a specific concrete program, you will find performance problems, and chances are they will have almost nothing whatever to do with these abstract questions. They will most likely all be things you could not have thought of a-priori.
For a specific example of this, look here.
If I could generalize from experience, a major source of performance problems is galloping generality.
That is, while data structure abstraction is generally considered a good thing, any good thing can be massively over-used, and then it becomes a crippling bad thing. This is not rare. In my experience it is typical.
I think you're answering big parts of your question on your own. I personally prefer easy-to-read code (even if you understand C style, maybe the next to read your code has more trouble with it) and safe code (which suggests stringstream, exceptions, smart pointers...)
If you really have something where it makes sense to consider bitwise operations - ok. But often I see C programmers use a char instead of a couple of bools. I do NOT like this.
Speed is important, but most of the time is usually required at a few hotspots in a program. So unless you measure that some technique is a problem (or you know pretty sure that it will become one) I would rather use what you call C++ style.
Why the expensiveness of exceptions is an argument? Exceptions are exceptions because they are rare. Their performance doesn't influence the overall performance. The steps you have to take to make your code exception-safe do not influence the performance either. But on the other hand exceptions are convenient and flexible.
This is not really an "answer", but if you work in a project where performance is important (e.g. embedded/games), people usually do the faster C way instead of the slower C++ way in the ways you described.
The exception may be bitwise operations, where not as much is gained as you might think. For example, "Don't use left-shift for multiplying by two." A half-way decent compiler will generate the same code for << 2 and * 2.
Is there a tool in either Linux/Windows that would enable us to determine if a logic of the particular function in C is same as that of a particular function in C++ ?
In general, the equivalence of Turing machines is undecidable, so no.
If you are just talking of control structures, if/else, blocks of code, swtich/case, while, for, etc AND if you are willing to be able to accept "gettign a good feel for it", rather than 100% accuray, then a picture may be work a thousand words, and you might look at a code to flowchart program.
I won't recommend any, as I don't know them well enough (but have always wanted to try them out, espcially if round trip. It might not be easy to find something free. In general, you will see something like this ... alt text http://www.ezprog.com/wp-content/uploads/flowchart.gif
is that what you have is mind? Do it for both C and C++ versions, and you can get a rough feel for similarity of logic.
Perhaps you can tell us a little more what exactly you are looking for? Help us to help you? Thanks.
You can imagine a tool that compares the structure of ASTs after the compiler has done the initial conversion to abstract representation or after one of more optimization passes.
This would probably
Miss some real matches (i.e. generate false negatives)
Identify some bogus matches (i.e. generate false positives)
With tuning you could force the second case to be more common. I have no feel for how good it would have to be to be useful as a front end to a vgrep process.
But it get worse, because you've asking for a cross-language implementation, and that will make it harder. Still, gcc uses the same abstract representation for everything, so it is not beyond imagining.
That said, I know of no such tool.
I think there is such a tool, called an assembly listing.
I've been working on a foundational c++ library for some time now, and there are a variety of ideas I've had that could really simplify the code writing and managing process. One of these is the concept of introducing some macros to help simplify statements that appear very often, but are a bit more complicated than should be necessary.
For example, I've come up with this basic macro to simplify the most common type of for loop:
#define loop(v,n) for(unsigned long v=0; v<n; ++v)
This would enable you to replace those clunky for loops you see so much of:
for (int i = 0; i < max_things; i++)
With something much easier to write, and even slightly more efficient:
loop (i, max_things)
Is it a good idea to use conventions like this? Are there any problems you might run into with different types of compilers? Would it just be too confusing for someone unfamiliar with the macro(s)?
IMHO this is generally a bad idea. You are essentially changing well known and understood syntax to something of your own invention. Before long you may find that you have re-invented the language. :)
No, not a good idea.
int max = 23;
loop(i, ++max)...
It is, however, a good idea to refactor commonly used code into reusable components and then reuse instead of copy. You should do this through writing functions similar to the standard algorithms like std::find(). For instance:
template < typename Function >
void loop(size_t count, Function f)
{
for (size_t i = 0; i < count, ++i) f();
}
This is a much safer approach:
int max = 23;
loop(++max, boost::bind(....));
I think you've provided one strong argument against this macro with your example usage. You changed the loop iterator type from int to unsigned long. That has nothing to do with how much typing you want to do, so why change it?
That cumbersome for loop specifies the start value, end value, type and name of the iterator. Even if we assume the final part will always be ++name, and we're happy to stick to that, you have two choices - remove some of the flexibility or type it all out every time. You've opted to remove flexibility, but you also seem to be using that flexibility in your code base.
I would say it depends upon whether you expect anyone else to ever have to make sense of your code. If it's only ever going to be you in there, then I don't see a problem with the macros.
If anyone else is ever going to have to look at this code, then the macros are going to cause problems. The other person won't know what they are or what they do (no matter how readable and obvious they seem to you) and will have to go hunting for them when they first run across them. The result will be to make your code unreadable to anyone but yourself - anyone using it will essentially have to learn a new language and program at the same time.
And since the chances of it just being you dealing with the code are pretty much nil if you hope the code to be a library that will be for more than just your personal use - then I'd go with don't.
In Unix, I find that by the time I want to create an alias for a command I use all the time, the command is on my fingers, and I'd have a harder time remembering the syntax of my alias than the original command.
The same applies here -- by the time you use an idiom so much that you want to create a macro for it, the idiom will be on you fingers and cause you more pain than just typing out the code.
Getting rid of the for loops is generally a good idea -- but replacing them with macros is not. I'd take a long, hard look at the standard library algorithms instead.
Apart from the maintenance/comprehension problems mentionned by others, you'll also have a hard time breaking and single-stepping through macro code.
One area where I think macros might be acceptable would be for populating large data structures with constants/litterals (when it can save an excessive amount of typing). You normally would not single-step through such code.
Steve Jessop makes a good point. Macros have their uses. If I may expound upon his statements, I would go so far as to say that the argument for or against macros comes down to "It depends". If you make your macros without careful thought, you risk making future maintaners' lives harder. On the other hand, using the wxWidgets library requires using library provided macros to connect your code with the gui library. In this case, the macros lower the barrier of entry for using the library, as magic whose innards are irrelevant to understanding how to work with the library are hidden away from the user. In this case, the user is saved from having to understand things they really don't need to know about, and can be argued that this is a "Good" use of macros. Also, wxWidgets clearly documents how these macros are supposed to be used. So make sure that what you hide isn't something that is going to need to be understood by someone else coming in.
Or, if its just for your use, knock yourself out.
It's a question of where you're getting your value. Is typing those 15 extra characters in your loops really what's slowing your development down? Probably not. If you've got multiple lines of confusing, unavoidable boilerplate popping up all over the place, then you can and should look for ways to avoid repeating yourself, such as creating useful functions, cleaning up your class hierarchies, or using templates.
But the same optimization rules apply to writing code as to running it: optimizing small things with little effect is not really a good use of time or energy.
I have to interview some C++ candidates over the next few weeks and as the most senior programmer in the company I'm expected to try and figure out whether these people know what they are doing.
So has anybody got any suggestions?
Personally I hate being left in a room to fill out some C++ questions so I'd rather do a more complex test that I can chat with the interviewee about their approaches and so forth as we go along. ie it doesn't matter whether they get the right answers or not its how they approach the problem that interests me. I don't care whether they understand obscure features of the language but I do care that they have a good solid understanding of pointers as well as understanding the under lying differences between pointers and references. I would also love to see how they approach optimisation of a given problem because solid fast code is a must, in my opinion.
So any suggestions along these lines would be greatly appreciated!
I wouldn't make them write code. Instead, I'd give them a couple of code snippets to review.
For example, the first would be about design by contract: See if they know what preconditions, postconditions and invariants are. Do a couple of small mistakes, such as never initializing an integer field but asserting that it is >= 0 in the invariant, and see if they spot them.
The second would be to give them bool contains(char * inString, char c). Implement it with a trivial loop. Then ask whether there are any mistakes. Of course, your code here does not check for null in the input parameter inString (even if the very previous question talked about preconditions!). Also, the loop finishes at character 0. Of course, the candidate should spot the possible problems and insist on using std::string instead of this char * crap. It's important because if they do complain, you'll know that they won't add their own char *'s to new code.
An alternative which addresses containers: give them a std::vector<int> and code which searches for prime numbers or counts the odd numbers or something. Make some small mistake. See if they find any issues and they understand the code. Ask in which situation a std::set would be better (when you are going to search elements quite systematically and original order of entrance doesn't matter.).
Discuss everything live, letting them think a couple minutes. Capture the essence of what they say. Don't focus on "coverage" (how many things they spot) because some people may be stressed. Listen to what they actually say, and see if it makes any sense.
I disagree with writing code in interviews. I'd never ask anyone to write code. I know my handwritten code would probably suck in a situation like that. Actually, I have seldom been asked to do so, but when I have, I haven't been hired.
This one is a great complex task, even though it is looking quite harmless.
I believe that a C++ programmer needs more than just generic programming skills, because...
In C++ it's harder to shoot yourself in the foot, but when you do, you blow off your whole leg.
Writing bug-free, maintainable C++ code places a much higher demand on a few areas than most languages.
One thing I'll call "pedanticness". You know how some people can spot spelling errors in something at a glance? A C++ programmer needs to be able to spot simple bugs while they read or write code (whether the code is their own or not). A programmer who relies on the "compile and test" technique just to get rid of simple bugs is incompatible with the C++ language, because those bugs don't always lead to immediate failure in C++.
C++ programmers also need a good knowledge of low-level stuff. Pointers, memory allocators, blocking, deadlocks. And "nitty gritty" C++ issues, like multiple inheritance and method hiding and such, particularly if they need to maintain other people's code.
Finally, C++ programmers need to be able to write code that's easy for other people to use. Can they design stuff well?
A good test for the first two areas is "Here's some C++ code I got off the internet. Find the bugs, and identify the unneccessary bits." (There's lots of really bad C++ code available on the internet, and often the programmer does unnecessary things due to a faulty understanding of how to be "safe" in C++.)
The last area you can test with more generic interview questions.
A few questions can allow you to know a lot about a candidate:
Differences between a pointer and a reference, when would you use each?
Why would you make a destructor virtual?
Where is the construction order of a class attributes defined?
Copy constructor and operator=. When would you implement them? When would you make them private?
When would you use smart pointers? what things would you take into account to decide which?
Where else have you seen RAII idiom?
When would you make a parameter const? when a method?
When would you make an attribute mutable?
What is virtual inheritance?
What is template specialization?
What are traits?
What are policies?
What is SFINAE?
What do you know about C++Ox standard?
What boost libraries have you used?
What C++ books have you read? (Sutter? Alexandrescu?)
Some short exercises (no more than 10 minutes) about STL containers, memory management, slicing, etc. would also be useful. I would allow him to do it in a computer with a ready environment. It's important to observe the agility.
Checkout Joel's Guerrilla guide to interviewing. Seems a lot like what you are looking for.
"Write a program that receives 3 integers in the range of 0..2^32-1, and validates if they represent valid edges of a triangle".
It seems to be a simple question. The input is considered valid if the sum of any two edges is greater than the third edge. However, there are some pitfalls, that a good programmer will handle:
The correct type to use should be unsigned long. Many "programmers" will fail here.
Zero values should be considered as non-valid.
Overflow should be avoided: "if (a+b <= c) return false" is problematic since a+b may cause an overflow.
if (a <= c-b) is also bad solution since c-b may be negative. Not a good thing for unsigned types.
if (c > b) { if (a <= c-b) return false; } else { if (a <= b-c) return false; } This looks much better, but it will not work correctly if (a >= b+c).
A good programmer must be detail oriented. This simple exercise will help checking if he is.
Depending on what your organisation's pre-screening is like, assume that the person knows nothing at all about C++ and has just put in on their CV because it makes them look supertechnical. Seriously. Start with something simple, like reversing a string. I have had candidates who couldn't even write a function prototype for this !!
Do not forget to also test for code bigotry. I know I don't want anyone working for or with me that isn't a flexible and consequently practical programmer both in their attitude to the programming language, but also in their approach to problem solving.
Denying any type of preconceptions
Understanding the value of the
exceptions in any Best Practices
Being capable of refusing long term
habits in favor of something else if
the need arises
These are characteristics dear to me. The manner of testing for these is not ideal if the interviews aren't lengthy or don't involve presenting code. But showing code snippets with purposely debatable techniques while offering a use case scenario and asking the candidate how they feel about the solution is one way.
This article offers some general ideas that are relevant regardless of what language you're working with.
Don't test only the C++ and overall technical skills! Those are of course important, but they are nothing if people don't listen, don't answer properly or don't follow the commitments they made.
Check at most for the ability to clearly communicate. If people cant tell you what roughly they did in their former jobs within a few minutes, they will also be unable to report about their work at your place etc.
In a recent company we invited people for interviews in groups of about 3 people together. They were surprised, but nobody was angry about that. It was very interesting, because people had to communicate not only with us, but also with others in the same position. In case we were interested further, we arranged a second interview.
You can choose potentially problematic task and see how they approach it. Ask them to write a smart pointer for example, you'll see if they understand pointers, references and templates in one step :) Usually they are stressed so they will do mistakes, those mistakes might help you find out how good they problem solving skills are, what paths would they use to fix a mistake and so on. The only problem with this approach is that sometimes interviewee just don't know anything about the task and you would have to quickly figure out something easier. If they do perfect code you can discuss their choices but when there's nothing to look at it is depressing for both of you.
Here is my answer to a similar question geared towards C#, but notice that my answer is language agnostic. My interview question is, in fact, in C. I rarely interview a person with the goal of finding out if they can program. I want to find out if they can think, problem solve, collaborate, communicate, understand something new, and so on. In the meantime, I circle around trying to see if they "get it" in terms of the big picture of software engineering. I use programming questions because that's a common basis and an easy ruse.
Get Codility.com to screen out non-programming programmers, this will get you a limited number of mostly reasoable candidates. Sit for an hour with each of them and try to build something together (a micro web server, a script for processing some of your data, a simple GUI). Pay attention to communication skills, i.e. how much effort does it take to understand the candidate. Ask the candidate for recommendation of books related to the subject (C++ software development in your case). Follow Guerilla Guide to Interviewing, i.e. answer yourself honestly, if the person is smart and gets things done. Good luck.
Check 10 C++ Interview Questions by Tests4Geeks.
It's an addition to their pre-interview C++ test and it has really usefull questions. Many people have been working on these interview questions so it's quite balanced and has no tricky or syntax questions.
Idea is quite simple - first you weed out incompetent candidates using the test, then you use article questions in real-life interview.
Whatever you do, pairing would be a good idea. Come up with a good program and pair with the guy and work towards solving the problem. IMHO, that a very good idea
So has anybody got any suggestions?
I'd recommend getting a copy of this:
http://www.amazon.co.uk/Programming-Interviews-Exposed-Secrets-Programmer/dp/047012167X/ref=sr_1_1?ie=UTF8&s=books&qid=1252499175&sr=8-1
ie it doesn't matter whether they get the right answers or not its how they approach the problem that interests me
You could ask the candidate to come up with a UML design to a common problem. If they show you a design pattern, then you can talk through the pros/cons of the pattern. You could then ask them to produce some code for one of the classes.
This would help you determine their technical knowledge level and their communication abilities.
I do care that they have a good solid understanding of pointers as well as understanding the under lying differences between pointers and references
Linked list problems are good for determining whether a candidate has a solid grasp of pointers.
As for references, you could show them some code that does not use references correctly, and ask them to describe the problem.
e.g show them a class definition that contains a reference member variable, and the implementation of the constructor with the reference initialization missing.
I would also love to see how they approach optimisation of a given problem because solid fast code is a must, in my opinion.
I'd start off simple...
Show them a code example that passes strings to a function by value. (the strings should not be modified in the function). You should check they correct the code to pass the strings by const reference.
After this, you could show a constructor that uses assignment instead of initialization (for objects). Ask them to improve it.
Lastly, ask them simple questions about data structure selection.
e.g. When they should use a list rather than a vector.
If you feel they have a grasp of the fundamentals you could either ask how they approach optimization problems (discuss profilers etc), or ask them to optimize something less obvious.
Take a look into this C++ test. They have a questions about differences between pointers and references as you require.
Here is full list of topics:
Fundamentals: References & Pointers, Const Correctness, Explicit
Standard Library
Class Design, Overloading
Virtual Functions, Polymorphism, Inheritance
Memory Management, Exception Safety
Miscellaneous: Perfect Forwarding, Auto, Flow Control, Macros
These guys are really serious about their questions, they also made the great list of C++ interview question which you might ask your candidates:
https://tests4geeks.com/cpp-interview-questions/
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
What guidelines do you follow to improve the general quality of your code? Many people have rules about how to write C++ code that (supposedly) make it harder to make mistakes. I've seen people insist that every if statement is followed by a brace block ({...}).
I'm interested in what guidelines other people follow, and the reasons behind them. I'm also interested in guidelines that you think are rubbish, but are commonly held. Can anyone suggest a few?
To get the ball rolling, I'll mention a few to start with:
Always use braces after every if / else statement (mentioned above). The rationale behind this is that it's not always easy to tell if a single statement is actually one statement, or a preprocessor macro that expands to more than one statement, so this code would break:
// top of file:
#define statement doSomething(); doSomethingElse
// in implementation:
if (somecondition)
doSomething();
but if you use braces then it will work as expected.
Use preprocessor macros for conditional compilation ONLY. preprocessor macros can cause all sorts of hell, since they don't allow C++ scoping rules. I've run aground many times due to preprocessor macros with common names in header files. If you're not careful you can cause all sorts of havoc!
Now over to you.
A few of my personal favorites:
Strive to write code that is const correct. You will enlist the compiler to help weed out easy to fix but sometimes painful bugs. Your code will also tell a story of what you had in mind at the time you wrote it -- valuable for newcomers or maintainers once you're gone.
Get out of the memory management business. Learn to use smart pointers: std::auto_ptr, std::tr1::shared_ptr (or boost::shared_ptr) and boost::scoped_ptr. Learn the differences between them and when to use one vs. another.
You're probably going to be using the Standard Template Library. Read the Josuttis book. Don't just stop after the first few chapters on containers thinking that you know the STL. Push through to the good stuff: algorithms and function objects.
Delete unnecessary code.
That is all.
Use and enforce a common coding style and guidelines. Rationale: Every developer on the team or in the firm is able to read the code without distractions that may occur due to different brace styles or similar.
Regularly do a full rebuild of your entire source base (i.e. do daily builds or builds after each checkin) and report any errors! Rationale: The source is almost always in a usable state, and problems are detected shortly after they are "implemented", where problem solving is cheap.
Turn on all the warnings you can stand in your compiler (gcc: -Wall is a good start but doesn't include everything so check the docs), and make them errors so you have to fix them (gcc: -Werror).
Google's style guide, mentioned in one of these answers, is pretty solid. There's some pointless stuff in it, but it's more good than bad.
Sutter and Alexandrescu wrote a decent book on this subject, called C++ Coding Standards.
Here's some general tips from lil' ole me:
Your indentation and bracketing style are both wrong. So are everyone else's. So follow the project's standards for this. Swallow your pride and setup your editor so that everything is as consistent as possible with the rest of the codebase. It's really really annoying having to read code that's indented inconsistently. That said, bracketing and indenting have nothing whatsoever to do with "improving your code." It's more about improving your ability to work with others.
Comment well. This is extremely subjective, but in general it's always good to write comments about why code works the way it does, rather than explaining what it does. Of course for complex code it's also good for programmers who may not be familiar with the algorithm or code to have an idea of what it's doing as well. Links to descriptions of the algorithms employed are very welcome.
Express logic in as straightforward a manner as possible. Ironically suggestions like "put constants on the left side of comparisons" have gone wrong here, I think. They're very popular, but for English speakers, they often break the logical flow of the program to those reading. If you can't trust yourself (or your compiler) to write equality compares correctly, then by all means use tricks like this. But you're sacrificing clarity when you do it. Also falling under this category are things like ... "Does my logic have 3 levels of indentation? Could it be simpler?" and rolling similar code into functions. Maybe even splitting up functions. It takes experience to write code that elegantly expresses the underlying logic, but it's worth working at it.
Those were pretty general. For specific tips I can't do a much better job than Sutter and Alexandrescu.
In if statements put the constant on the left i.e.
if( 12 == var )
not
if( var == 12 )
Beacause if you miss typing a '=' then it becomes assignment. In the top version the compiler says this isn't possible, in the latter it runs and the if is always true.
I use braces for if's whenever they are not on the same line.
if( a == b ) something();
if( b == d )
{
bigLongStringOfStuffThatWontFitOnASingleLineNeatly();
}
Open and close braces always get their own lines. But that is of course personal convention.
Only comment when it's only necessary to explain what the code is doing, where reading the code couldn't tell you the same.
Don't comment out code that you aren't using any more. If you want to recover old code, use your source control system. Commenting out code just makes things look messy, and makes your comments that actually are important fade into the background mess of commented code.
Use consistent formatting.
When working on legacy code employ the existing style of formatting, esp. brace style.
Get a copy of Scott Meyer's book Effective C++
Get a copy of Steve MConnell's book Code Complete.
There is also a nice C++ Style Guide used internally by Google, which includes most of the rules mentioned here.
Start to write a lot of comments -- but use that as an opportunity to refactor the code so that it's self explanatory.
ie:
for(int i=0; i<=arr.length; i++) {
arr[i].conf() //confirm that every username doesn't contain invalid characters
}
Should've been something more like
for(int i=0; i<=activeusers.length; i++) {
activeusers[i].UsernameStripInvalidChars()
}
Use tabs for indentations, but align data with spaces
This means people can decide how much to indent by changing the tab size, but also that things stay aligned (eg you might want all the '=' in a vertical line when assign values to a struct)
Allways use constants or inline functions instead of macros where posible
Never use 'using' in header files, because everything that includes that heafer will also be affected, even if the person includeing your header doesn't want all of std (for example) in their global namespace.
If something is longer than about 80 columes, break it up into multiple lines eg
if(SomeVeryLongVaribleName != LongFunction(AnotherVarible, AString) &&
BigVaribleIsValid(SomeVeryLongVaribleName))
{
DoSomething();
}
Only overload operators to make them do what the user expects, eg overloading the + and - operators for a 2dVector is fine
Always comment your code, even if its just to say what the next block is doing (eg "delete all textures that are not needed for this level"). Someone may need to work with it later, posibly after you have left and they don't want to find 1000's of lines of code with no comments to indicate whats doing what.
setup coding convention and make everyone involved follow the convention (you wouldn't want reading code that require you to figure out where is the next statement/expression because it is not indented properly)
constantly refactoring your code (get a copy of Refactoring, by Martin Fowler, pros and cons are detailed in the book)
write loosely coupled code (avoid writing comment by writing self-explanatory code, loosely coupled code tends to be easier to manage/adapt to change)
if possible, unit test your code (or if you are macho enough, TDD.)
release early, release often
avoid premature optimization (profiling helps in optimizing)
In a similar vein you might find some useful suggestions here: How do you make wrong code look wrong? What patterns do you use to avoid semantic errors?
Where you can, use pre-increment instead of post-increment.
I use PC-Lint on my C++ projects and especially like how it references existing publications such as the MISRA guidelines or Scott Meyers' "Effective C++" and "More Effective C++". Even if you are planning on writing very detailed justifications for each rule your static analysis tool checks, it is a good idea to point to established publications that your user trusts.
Here is the most important piece of advice I was given by a C++ guru, and it helped me in a few critical occasions to find bugs in my code:
Use const methods when a method is not supposed to modify the object.
Use const references and pointers in parameters when the object is not supposed to modify the object.
With these 2 rules, the compiler will tell you for free where in your code the logic is flawed!
Also, for some good techniques you might follow Google's blog "Testing on the Toilet".
Look at it six months later
make sure you indent properly
Hmm - I probably should have been a bit more specific.
I'm not so much looking for advice for myself - I'm writing a static code analysis tool (the current commercial offerings just aren't good enough for what I want), and I'm looking for ideas for plugins to highlight possible errors in the code.
Several people have mentioned things like const correctness and using smart pointers - that's the kind of think I can check for. Checking for indentation and commenting is a bit harder to do (from a programming point of view anyway).
Smart pointers have a nice way of indicating ownership very clearly. If you're a class or a function:
if you get a raw pointer, you don't own anything. You're allowed to use the pointee, courtesy of your caller, who guarantees that the pointee will stay alive longer than you.
if you get a weak_ptr, you don't own the pointee, and on top of that the pointee can disappear at any time.
if you get a shared_ptr, you own the object along with others, so you don't need to worry. Less stress, but also less control.
if you get an auto_ptr, you are the sole owner of the object. It's yours, you're the king. You have the power to destroy that object, or give it to someone else (thereby losing ownership).
I find the case for auto_ptr particularly strong: in a design, if I see an auto_ptr, I immediately know that that object is going to "wander" from one part of the system to the other.
This is at least the logic I use on my pet project. I'm not sure how many variations there can be on the topic, but until now this ruleset has served me well.