some C++ syntax questions [closed] - c++

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 10 years ago.
i'm an undergrad engineering student taking a senior/graduate-level CS course on simulation, and am in way over my head. I know that all of these can be found by searching resources online, but they are all such disjoint and shallow questions that it has proven difficult.
I'm just hoping for a few quick answer to a few questions.
I've seen "&" used a few different ways (address location, and to make permanent changes to variables passed as local variables into functions), but I have no idea what it does in this context. Event is a class.
bool operator>( const Event& e ) const {
return simulation_time > e.simulation_time;
}
After typing this out I realized that that operator is being applied to a pointer (address).. so it seems that "const Event& e" is equivalent to "const Event &e" (which I know is equivalent to "const Event & e")?
that is evil.
Next: what is the benefit of using const in such a straight forward situation?
an excerpt from a program:
my_heap->insert_event(event1);
[my_heap is an instance of a class which contains a vector based heap (and a function insert_event, which adds the event to the heap).]
What does the "->" mean?
All of the examples on pointers that I have seen go something like
int i = 2
int *p;
p = &i;
which is fine and dandy, but I've got this going on:
MinHeap *my_heap = new MinHeap();
and I don't understand what it's saying. I really can't even formulate an intelligent question. It just doesnt seem to me that it's pointing to an address at all...
-------------------------------
thanks in advance to anyone who takes the time to respond

The & operator
Has 2 primary uses: one is to take the address of a variable in memory, as you seem to be aware. So if I have int count = 0; the value of count is 0, but where is this variable in memory? &count will return this address, which can be useful in a variety of ways.
The other use is to declare/define a reference to a type. Note that in this context & is no longer an operator, and can not be given custom behavior in a user defined class. int & myRef represents a reference to an integer, which is very much like a pointer, but instead of having a variable to hold some address in memory, you are using one variable as a sort of pseudonym for another. int &myRef = count;, after this, count and myRef can be used 100% interchangeably. Note that this use only comes when defining or declaring a variable, never as the right hand side of an expression, or in other contexts. As you noted, whitespace is ignored for references, which is the same behavior as pointers.
const
It's always good behavior to use const when you can (in my opinion). It makes clear how variables will be used. Imagine if you have a function void foo(int & someIntRef) or void foo(int * someIntPtr). When I call foo, it is not guaranteed that the variable I pass in won't be changed. Maybe the integer I am passing in is something I am keeping track of very closely, and don't want anyone else to maybe or maybe not change it, so I would be forced to copy it to ensure the definition of foo, which I may not even have access to, doesn't alter the variable. In most situations, if I saw this function signature, I would assume the function would alter my variable. Also, there is a performance benefit if the compiler knows a function parameter is const, but as you are new to c++ it might be best to not worry about exactly how/why at this point.
-> operator
This is an operator (note, it may be overridden in custom classes, but it's very rare) that almost always access a data member or member function of a pointer to an object. If I have a struct:
struct Shape
{
int mSideCount;
};
...
Shape SomeShape;
Shape * ptrShape = &SomeShape;
I can access the mSideCount data member of SomeShape with SomeShape.mSideCount. But what about ptrShape? It's not a Shape, it's a pointer (specifically, Shape *). I have to dereference it first, with the * operator, like (*ptrShape).mSideCount. It's kinda ugly. To make life easier, -> exists to combine the dereference and member access: ptrShape->mSideCount.
new operator
new allocates memory for an object, and ensures it is constructed correctly (calls an appropriate constructor for the object, which is a member function that looks like Shape(){} in the case of the Shape example above). The big difference is where the memory comes from. When you create a variable like SomeShape above, it is created in a section of memory called the stack (hence, stack overflow). The stack usually has a relatively small maximum size, and any variables declared on the stack go away once the block (inside function brackets, loop brackets, whatever the block is) ends, so can't be use in other functions easily. new on the other hand by default creates the object using memory on the heap, which is more closely "all the memory on your system". There are books written about memory management and architecture alone, so this is an extremely brief introduction.
As many others have noted - these are fairly basic c++ concepts. You will be back here soon when you see other even less common language features. Get a good book, read through it, understand everything it says, do some of the examples, and then come here to fill in gaps in your knowledge that you still can't wrap your head around. I personally like c++ Dietle and Dietle, but anything will help you.

There is no difference between const Event& e and const Event &e.
Arrow operator -> is class member access operator used for pointers.

what is the benefit of using const in such a straight forward
situation?
This situation is called passing an argument by constant reference. Passing arguments just by value causes a copy to be made of that argument and that copy is used within the function. Passing by constant reference passes a reference to a function that is const - that means that the object is not copied. The const part ensures that you are not able to modify the reference argument (in the same way that you cannot change a regular constant variable)
MinHeap *my_heap = new MinHeap();
This is dynamic memory allocation. The new operator creates memory on the heap in which to place a new object of type MinHeap. After the space is allocated the new operator also calls the constructor that class and the returns a pointer to that object which you store as my_heap in your code. You then can modify the object that your pointer points to using the -> operator.
You should really consider buying an introductory text on C++ where these things are described in more detail

Related

Make struct object thread safe

I have a function call
void moveMeToThread(UnsafeStruct *ptr)
{
// do stuff with ptr
}
Now I want to move moveMeToThread to a different thread, so I do not want anyone creating an object of UnsafeStruct on the stack and I also want memory of all UnsafeStruct objects made on the heap to be freed automatically. Anyone have an elegant way to do this?
Sounds like you'd like to make a heap-only class. There are many ways to force this:
you might make private ctors (all of them!) and create a static create() function that returns a pointer (sometimes called named ctor)
you might make dtor private
The latter technically does not save you from placement new to a suitable memory block, but otherwise protects from sensible coding mistakes and is way more compatible with algorithms and containers. E.g. you can still copy such an object via copy ctor outside the class, which is not possible if you make all ctors private (which is a requirement for the first version).
You might do this:
template<typename T>
class HeapOnly
{
public:
T t;
operator T&() { return t; }
operator const T&() const { return t; }
private:
~HeapOnly();
};
void moveMeToThread(HeapOnly<UnsafeStruct> *ptr)
{ /* ... */ }
int main()
{
HeapOnly<UnsafeStruct> *ptr =
new HeapOnly<UnsafeStruct>{/* args to UnsafeStruct */};
moveToThread(ptr);
}
Small note: there's no such thing as (call/parameter) stack in the C++ standard. It only appears in ItaniumABI (and potentially in other ABIs). Standard says ASDV (automatic storage duration variables) for what's commonly referred to as 'on the stack', but nothing prevents an implementation to allocate the memory on the stack (as long as compiler can prove that the object's lifetime cannot extend the stack unroll - this works e.g. if it's allocated before static initialization). It might be completely unimportant in your case, but in security-related codes, where buffer overflow is important, you can't strictly enforce not having objects allocated from the same stack this way (and thus it's suggested to do a runtime check) - but you can still enforce that the object is allocated via new (or the given static member function).
I do not want anyone creating an object of UnsafeStruct on the stack.
I want to forbid it because if someone creates an object on the stack and sends it on the thread, it can cause a crash(dangling pointer)
Do you also want to prevent anybody from creating int variables on the stack? Because if somebody creates an int variable on the stack, and if they allow a reference or a pointer to it to outlive the stack frame that contains the variable, then their program could crash.
Seriously.
That problem is older than C++. That problem has existed since the very first edition of the C programming language. Every C and C++ programmer has to learn not to do that. Always have. Always will.
In some languages (e.g., Java, Python), No object of any kind can be allocated anywhere else except the garbage-collected heap. Variables can only hold references to objects, and dangling references are impossible. Programmers in those languages expect an assignment a=b to copy an object reference. That is, after the assignment, a and b both refer to the same object.
That's not the C++ way. C++ programmers expect that if some type T is publicly constructable, then they expect to be allowed to declare one wherever they want. And when they see a=b, they think of that assignment operator as copying a value. They expect that after the assignment, a and b still are two different objects that both have (in some sense) the same "value."
You will find more people saying positive things about your library if you design it to work in that same way.

C++ references and exiting scoping

I'm getting to grips with references in C++ and I have a small query surrounding references & scoping, for this it's probably best to create an example:
Imagine I have a method in "BankDatabase.cpp" which takes a bank record by reference and adds it to a data structure (also by reference).
void AddRecord( BankRecord& bankRecord )
{
//Add record to data structure by reference
}
If I run a method like so:
void TestAddRecord( BankDatabase& bankDatabase )
{
BankRecord bankRecord { "John", "Doe", 9999 }
bankDatabase.AddRecord( bankRecord );
}
To my mind, "bankRecord" falls out of scope (as do its two strings and int) and is thus cleared from memory at the end of the "TestAddRecord" method, leaving "bankDatabase" pointing at some empty memory?
If so what's the general accepted standard / resolution to such a scenario? It seems a little mad to have to pass things by value...
In that case passing by value seems like the way to go. Allocating a new BankRecord pointer will work too. Storing things by reference is not very great.
However if I'm not mistaking, your two strings and the int won't be lost since they are present in the stack and will not be deallocated. But bankRecord will still be lost.
The best way to answer these concerns is to step through the code in the debugger and see what the Vector is doing with the variable being appended. Look especially at the constructor calls as you step into the data structure's Append functions. Because I do not know your underlying data structure, it is a bit more difficult for me to tell you more information. I will assume it is a std::vector for now until told otherwise.
You may be surprised to learn that references passed through a function do not tell the entire story about when it will go in and out of scope. I often think of C++ references as pointers that do not need nullptr checks.
Your code will work fine as long as the reference is copied into the vector or does not go out of scope because the variable it pointed to was destroyed. The reference will not go out of scope if it is referring to a member variable or memory on the heap for your particular case.
If the reference was declared on the stack to a variable created on the stack, and then appended to the vector, then you will have scope problems.
You should also look into emplace() if you have C++11 and the compiler supports move semantics.
In short, the most important thing you can do here is step through the code and see what Constructors are being called. This will give you the answer you desire.

C++ Passing pointers / Constants. Efficiency

I am working on a project with a friend that does a lot of computation and we are using c++ for it. I havent used c++ in a while and he is suggesting some fixes. I hoped I could come here for a more in depth explanation and maybe could be linked to some more articles.
He says its more efficient instead of having this
Hand::Hand(Card one, Card two)
To have this
Hand::Hand(const Card &one, const Card &two)
Is this correct? What about passing a constant address rather than the object itself makes it more efficient? He mentioned passing a reference instead of making a copy. If I dont pass by address, will it construct a new card object as a copy of the one I've passed?
Also
Instead of
bool Hand::hasFourKind(Card board[])
Have this
bool Hand::hasFourKind(const Card *board)
This passes a pointer to the start of the array instead of making an array copy?
In most cases, if you don't need a local variable to be modified, the latter method of the first example is faster, because the entire object will not have to be copied on the stack for the function to use it. Instead, a pointer will be pushed onto the stack, which takes less time. (Although some calling conventions allow passing small arguments in registers, which is even faster.)
For small objects, the time spent in copying may not be an issue, but may be more evident for large classes/structs.
The second examples have identical operation (disregarding the constness), since the array would not be passed by value in any case. It would be passed as a simple pointer, or passed "by reference."
From an optimisation point of view, the compiler can not rely on const actually meaning "won't change". const_cast allows a function to alter the const-ness of something, such that it can be altered. It is useful for the programmer to know that "I get an error if I accidentally modify this" (in particular mistyping if (a = b) instead of if (a == b)).
If the source code of a function is available to the compiler, it can itself prove that a value isn't being changed, or is being changed, regardless of whether you mark it const or not.
In a video with Chandler Carruth (one of the currently most active developers of Clang and LLVM), he actually promotes using non-reference calls for any type that is reasonably small. Often, the compiler will optimise away the copy of the argument anyways, because the reference MAY be modified [so if the compiler doesn't have the source code available, it won't know if the value is being changed or not]
Whether you use Card board[] or Card *board will not change things, the compiler will generate exactly the same code either way - if you want others reading the code to understand if the function is expected to modify the value or not, then add const for values that aren't being changed.
This
Hand::Hand(const Card &one, const Card &two)
is more efficient than this
Hand::Hand(Card one, Card two)
For 2 reasons
it avoids making a copy of the Cards
If you wanted to maintain a Deck of cards, it is possibe with the first method but not possible with the second method for reasons explained by my first point
This
bool Hand::hasFourKind(Card board[])
is equivalent to this
bool Hand::hasFourKind(const Card *board)
because they both represent array of cards, but the first one is just syntatic sugar for pointer to cards, so they both actually represent pointer to cards.
The second is better because it implies that the board cannot be modified by anyone else. This is not really much of a guard because of const_cast which can be used to remove the constness of an object.
If you really wanted to ensure that the cards cannot be modified by anybody in that method, then I would suggest you change design a bit to enable this:
bool Hand::hasFourKind() const;
Where the cards are part of the Hand class and cannot be modified by anyone

What is the point of having both points to and dot operator? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I know the difference between the points-to (->) and dot (.) operator but I don't see why the need for the two arrises? Isn't it always just as easy not to use pointers and just use the dot operator? From http://www.programcreek.com/2011/01/an-example-of-c-dot-and-arrow-usage/
#include <iostream>
using namespace std;
class Car
{
public:
int number;
void Create()
{
cout << "Car created, number is: " << number << "\n" ;
}
};
int main() {
Car x;
// declares x to be a Car object value,
// initialized using the default constructor
// this very different with Java syntax Car x = new Car();
x.number = 123;
x.Create();
Car *y; // declare y as a pointer which points to a Car object
y = &x; // assign x's address to the pointer y
(*y).Create(); // *y is object
y->Create();
y->number = 456; // this is equal to (*y).number = 456;
y->Create();
}
Why ever bother using pointers? Just create Y as X was, it would work the same. If you say you need pointers for dynamically alocated memory, then why bother having the dot operator?
I think you're mixing two separate concerns.
First, the -> operator is unnecessary, yes. x->y is equivalent to (*x).y, but the -> operator is easier to type, so it's basically just a convenience.
The second part is whether to use pointers at all.
And you're right, often you shouldn't. By default, just create your objects then and there, and refer to them direclty:
Foo bar;
bar.baz():
but pointers are still necessary for a lot of cases. Objects need to be able to reference other objects. A reference can do that, but it can't be reseated. Once it is initialized, it will always point to the same object.
A pointer can be updated to point to a different object.
Linked lists, tree data structures and countless other things depend on objects being able to point to other objects.
So yes, we need pointers. But we don't need the -> operator. We just use it because it's convenient.
a. it just makes it easier to semantically understand the code without looking at the types, or having special notations like m_pszMyName. You can instantly tell reading the code what is a pointer and what is a value.
b. Think of the case of shared_ptr and overriding operators. shared_ptr<T>->get() means something else than shared_ptr<T>.get(). The first being the function in a pointed object, the second one being the function of the shared_ptr class itself. This is just one example, but you see the point.
From your link:
The following example should be a good one.
It is actually a bit confusing. Why would you ever create an object on the stack (Car x;) and then create a pointer to it to access it using ->?
Instead of trying to answer the implied question "Why do we need pointers?" I'll try to clear up any confusion that might have arisen from that example.
In your comment you say:
I'm wondering if there's a difference between objects that are created differently.
In the example there is only one object, the Car on the stack created by Car x; (to be complete there is also a Car-pointer on the stack, created by Car *y;). They go out of scope when main() exits, so their memory gets cleaned up.
But there is another way to create objects, which I guess you already know about based on your comment, and this is to use new to initialize them on the heap: Car *z = new Car;. Objects on the heap will never go out of scope, so you can keep using them after the function that called new exited, but you have to explicitly clean them up using delete to prevent memory leaks.
So there it is, a more realistic use of a pointer to an object: the return value of new.
Isn't it always just as easy not to use pointers and just use the dot
operator?
C/C++ like other higher order languages do not encapsulate the pointers with some sugar coating syntax. Pointer's arise naturally and the list below is not exhaustive
Allocating memory from heap. Static data allocation, or allocating storage in stack is always not feasible. There are overheads with transfer of ownership, space constraint and dynamic nature of your program.
Reading and writing files.
Iterating over objects including C-Type string. You can use array access syntax, but there is little safety difference and arrays are degenerated to pointers when you pass to a function(size information is lost).
All the above can be encapsulated into objects when you thing from C++ perspective.
FILE IO through iotream
pointers through smart pointers(some from the C++98 and some in C++11 or eve boost)
Iterators for STL Type Objects.
Using reference
Nevertheless, Pointers are there even in languages where you don't see them explicitly. They are just encapsulated to higher order objects.
This explains to some extent why we can't think beyond pointers, the next part probably you are interested is in the syntax. Why do we atall need ptr->somemember instead of (*ptr).somemember.
Its just shorthand for a repetitive usage. C/C++ programmers have got used to it and I have not seen till to date a single program using the superfluous syntax.
-> is just for short. Consider a class represent nodes of trees:
struct node {
int data;
node* left;
node* right;
};
The member left is a pointer point to the left child of the node. Suppose we have a pointer to some node p, now we want to get the pointer point to the right child of the left child of the left child of p, using dot we have to write (*(*(*p).left).left).right, difficult to read and error-prone, using -> we can simply write p->left->left->right, very clear.
The existence of both -> and . operators in C++ is a direct influence from C. C makes the distinction between accessing an object through a pointer and accessing an object which is declared in the current scope.
In C++ references are a natural extension of accessing locally scoped objects.
I don't know whether the creators of C considered this, but I always used to use it as a small optimisation guide. Looking at a piece of code, you could see that -> would calculate the final address at runtime, whereas the . operator would calculate the address at compile time. This even works when accessing members of structures. Consider the following: myptr->mMember.mValue The offset from mMember to mValue can be calculated at compile time, whereas the final address calculation from the pointer must be calculated at run time. A minor consideration as far as optimisation is concerned these days, I'll admit, and with references in C++ it's no longer possible to do this, but 20 years ago it was something to bear in mind.
Yes, you could always use (*x).member instead of x->member, but would you really want to when x is a complex expression?
Having related things (* and . in this case) far away makes the source code less readable, so having the -> "in one place" is simply a nicer syntax.
As for the need for the concept of pointers, there are 2 main reasons:
1. Object Lifetime
There are two ways to allocate an object
On the stack.
In the dynamic memory.
The stack winds and unwinds as the flow of execution enters and exits functions, so the lifetime of a stack object is inevitably married to how long we stay in the function that created it.
If you need an object that lives longer than the function that created it, you need to create it in the dynamic memory, and the only way to identify such object is by its memory address, aka. pointer.
2. Object Sharing
Is there more than one other object that needs to access the object? If yes, then there is no way for these other objects to reference the shared object, other than holding its address.
Even if you have only one other object, but their lifetimes differ, the "lifetime" reason applies. If there is only one other object and their lifetimes match, than make it a field.

What C++ pitfalls should I avoid? [closed]

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 11 years ago.
I remember first learning about vectors in the STL and after some time, I wanted to use a vector of bools for one of my projects. After seeing some strange behavior and doing some research, I learned that a vector of bools is not really a vector of bools.
Are there any other common pitfalls to avoid in C++?
A short list might be:
Avoid memory leaks through use shared pointers to manage memory allocation and cleanup
Use the Resource Acquisition Is Initialization (RAII) idiom to manage resource cleanup - especially in the presence of exceptions
Avoid calling virtual functions in constructors
Employ minimalist coding techniques where possible - for example, declaring variables only when needed, scoping variables, and early-out design where possible.
Truly understand the exception handling in your code - both with regard to exceptions you throw, as well as ones thrown by classes you may be using indirectly. This is especially important in the presence of templates.
RAII, shared pointers and minimalist coding are of course not specific to C++, but they help avoid problems that do frequently crop up when developing in the language.
Some excellent books on this subject are:
Effective C++ - Scott Meyers
More Effective C++ - Scott Meyers
C++ Coding Standards - Sutter & Alexandrescu
C++ FAQs - Cline
Reading these books has helped me more than anything else to avoid the kind of pitfalls you are asking about.
Pitfalls in decreasing order of their importance
First of all, you should visit the award winning C++ FAQ. It has many good answers to pitfalls. If you have further questions, visit ##c++ on irc.freenode.org in IRC. We are glad to help you, if we can. Note all the following pitfalls are originally written. They are not just copied from random sources.
delete[] on new, delete on new[]
Solution: Doing the above yields to undefined behavior: Everything could happen. Understand your code and what it does, and always delete[] what you new[], and delete what you new, then that won't happen.
Exception:
typedef T type[N]; T * pT = new type; delete[] pT;
You need to delete[] even though you new, since you new'ed an array. So if you are working with typedef, take special care.
Calling a virtual function in a constructor or destructor
Solution: Calling a virtual function won't call the overriding functions in the derived classes. Calling a pure virtual function in a constructor or desctructor is undefined behavior.
Calling delete or delete[] on an already deleted pointer
Solution: Assign 0 to every pointer you delete. Calling delete or delete[] on a null-pointer does nothing.
Taking the sizeof of a pointer, when the number of elements of an 'array' is to be calculated.
Solution: Pass the number of elements alongside the pointer when you need to pass an array as a pointer into a function. Use the function proposed here if you take the sizeof of an array that is supposed to be really an array.
Using an array as if it were a pointer. Thus, using T ** for a two dimentional array.
Solution: See here for why they are different and how you handle them.
Writing to a string literal: char * c = "hello"; *c = 'B';
Solution: Allocate an array that is initialized from the data of the string literal, then you can write to it:
char c[] = "hello"; *c = 'B';
Writing to a string literal is undefined behavior. Anyway, the above conversion from a string literal to char * is deprecated. So compilers will probably warn if you increase the warning level.
Creating resources, then forgetting to free them when something throws.
Solution: Use smart pointers like std::unique_ptr or std::shared_ptr as pointed out by other answers.
Modifying an object twice like in this example: i = ++i;
Solution: The above was supposed to assign to i the value of i+1. But what it does is not defined. Instead of incrementing i and assigning the result, it changes i on the right side as well. Changing an object between two sequence points is undefined behavior. Sequence points include ||, &&, comma-operator, semicolon and entering a function (non exhaustive list!). Change the code to the following to make it behave correctly: i = i + 1;
Misc Issues
Forgetting to flush streams before calling a blocking function like sleep.
Solution: Flush the stream by streaming either std::endl instead of \n or by calling stream.flush();.
Declaring a function instead of a variable.
Solution: The issue arises because the compiler interprets for example
Type t(other_type(value));
as a function declaration of a function t returning Type and having a parameter of type other_type which is called value. You solve it by putting parentheses around the first argument. Now you get a variable t of type Type:
Type t((other_type(value)));
Calling the function of a free object that is only declared in the current translation unit (.cpp file).
Solution: The standard doesn't define the order of creation of free objects (at namespace scope) defined across different translation units. Calling a member function on an object not yet constructed is undefined behavior. You can define the following function in the object's translation unit instead and call it from other ones:
House & getTheHouse() { static House h; return h; }
That would create the object on demand and leave you with a fully constructed object at the time you call functions on it.
Defining a template in a .cpp file, while it's used in a different .cpp file.
Solution: Almost always you will get errors like undefined reference to .... Put all the template definitions in a header, so that when the compiler is using them, it can already produce the code needed.
static_cast<Derived*>(base); if base is a pointer to a virtual base class of Derived.
Solution: A virtual base class is a base which occurs only once, even if it is inherited more than once by different classes indirectly in an inheritance tree. Doing the above is not allowed by the Standard. Use dynamic_cast to do that, and make sure your base class is polymorphic.
dynamic_cast<Derived*>(ptr_to_base); if base is non-polymorphic
Solution: The standard doesn't allow a downcast of a pointer or reference when the object passed is not polymorphic. It or one of its base classes has to have a virtual function.
Making your function accept T const **
Solution: You might think that's safer than using T **, but actually it will cause headache to people that want to pass T**: The standard doesn't allow it. It gives a neat example of why it is disallowed:
int main() {
char const c = ā€™cā€™;
char* pc;
char const** pcc = &pc; //1: not allowed
*pcc = &c;
*pc = ā€™Cā€™; //2: modifies a const object
}
Always accept T const* const*; instead.
Another (closed) pitfalls thread about C++, so people looking for them will find them, is Stack Overflow question C++ pitfalls.
Some must have C++ books that will help you avoid common C++ pitfalls:
Effective C++
More Effective C++
Effective STL
The Effective STL book explains the vector of bools issue :)
Brian has a great list: I'd add "Always mark single argument constructors explicit (except in those rare cases you want automatic casting)."
Not really a specific tip, but a general guideline: check your sources. C++ is an old language, and it has changed a lot over the years. Best practices have changed with it, but unfortunately there's still a lot of old information out there. There have been some very good book recommendations on here - I can second buying every one of Scott Meyers C++ books. Become familiar with Boost and with the coding styles used in Boost - the people involved with that project are on the cutting edge of C++ design.
Do not reinvent the wheel. Become familiar with the STL and Boost, and use their facilities whenever possible rolling your own. In particular, use STL strings and collections unless you have a very, very good reason not to. Get to know auto_ptr and the Boost smart pointers library very well, understand under which circumstances each type of smart pointer is intended to be used, and then use smart pointers everywhere you might otherwise have used raw pointers. Your code will be just as efficient and a lot less prone to memory leaks.
Use static_cast, dynamic_cast, const_cast, and reinterpret_cast instead of C-style casts. Unlike C-style casts they will let you know if you are really asking for a different type of cast than you think you are asking for. And they stand out viisually, alerting the reader that a cast is taking place.
The web page C++ Pitfalls by Scott Wheeler covers some of the main C++ pitfalls.
Two gotchas that I wish I hadn't learned the hard way:
(1) A lot of output (such as printf) is buffered by default. If you're debugging crashing code, and you're using buffered debug statements, the last output you see may not really be the last print statement encountered in the code. The solution is to flush the buffer after each debug print (or turn off the buffering altogether).
(2) Be careful with initializations - (a) avoid class instances as globals / statics; and (b) try to initialize all your member variables to some safe value in a ctor, even if it's a trivial value such as NULL for pointers.
Reasoning: the ordering of global object initialization is not guaranteed (globals includes static variables), so you may end up with code that seems to fail nondeterministically since it depends on object X being initialized before object Y. If you don't explicitly initialize a primitive-type variable, such as a member bool or enum of a class, you'll end up with different values in surprising situations -- again, the behavior can seem very nondeterministic.
I've already mentioned it a few times, but Scott Meyers' books Effective C++ and Effective STL are really worth their weight in gold for helping with C++.
Come to think of it, Steven Dewhurst's C++ Gotchas is also an excellent "from the trenches" resource. His item on rolling your own exceptions and how they should be constructed really helped me in one project.
Using C++ like C. Having a create-and-release cycle in the code.
In C++, this is not exception safe and thus the release may not be executed. In C++, we use RAII to solve this problem.
All resources that have a manual create and release should be wrapped in an object so these actions are done in the constructor/destructor.
// C Code
void myFunc()
{
Plop* plop = createMyPlopResource();
// Use the plop
releaseMyPlopResource(plop);
}
In C++, this should be wrapped in an object:
// C++
class PlopResource
{
public:
PlopResource()
{
mPlop=createMyPlopResource();
// handle exceptions and errors.
}
~PlopResource()
{
releaseMyPlopResource(mPlop);
}
private:
Plop* mPlop;
};
void myFunc()
{
PlopResource plop;
// Use the plop
// Exception safe release on exit.
}
The book C++ Gotchas may prove useful.
Here are a few pits I had the misfortune to fall into. All these have good reasons which I only understood after being bitten by behaviour that surprised me.
virtual functions in constructors aren't.
Don't violate the ODR (One Definition Rule), that's what anonymous namespaces are for (among other things).
Order of initialization of members depends on the order in which they are declared.
class bar {
vector<int> vec_;
unsigned size_; // Note size_ declared *after* vec_
public:
bar(unsigned size)
: size_(size)
, vec_(size_) // size_ is uninitialized
{}
};
Default values and virtual have different semantics.
class base {
public:
virtual foo(int i = 42) { cout << "base " << i; }
};
class derived : public base {
public:
virtual foo(int i = 12) { cout << "derived "<< i; }
};
derived d;
base& b = d;
b.foo(); // Outputs `derived 42`
The most important pitfalls for beginning developers is to avoid confusion between C and C++. C++ should never be treated as a mere better C or C with classes because this prunes its power and can make it even dangerous (especially when using memory as in C).
Check out boost.org. It provides a lot of additional functionality, especially their smart pointer implementations.
PRQA have an excellent and free C++ coding standard based on books from Scott Meyers, Bjarne Stroustrop and Herb Sutter. It brings all this information together in one document.
Not reading the C++ FAQ Lite. It explains many bad (and good!) practices.
Not using Boost. You'll save yourself a lot of frustration by taking advantage of Boost where possible.
Be careful when using smart pointers and container classes.
Avoid pseudo classes and quasi classes... Overdesign basically.
Forgetting to define a base class destructor virtual. This means that calling delete on a Base* won't end up destructing the derived part.
Keep the name spaces straight (including struct, class, namespace, and using). That's my number-one frustration when the program just doesn't compile.
To mess up, use straight pointers a lot. Instead, use RAII for almost anything, making sure of course that you use the right smart pointers. If you write "delete" anywhere outside a handle or pointer-type class, you're very likely doing it wrong.
Read the book C++ Gotchas: Avoiding Common Problems in Coding and Design.
Blizpasta. That's a huge one I see a lot...
Uninitialized variables are a huge mistake that students of mine make. A lot of Java folks forget that just saying "int counter" doesn't set counter to 0. Since you have to define variables in the h file (and initialize them in the constructor/setup of an object), it's easy to forget.
Off-by-one errors on for loops / array access.
Not properly cleaning object code when voodoo starts.
static_cast downcast on a virtual base class
Not really... Now about my misconception: I thought that A in the following was a virtual base class when in fact it's not; it's, according to 10.3.1, a polymorphic class. Using static_cast here seems to be fine.
struct B { virtual ~B() {} };
struct D : B { };
In summary, yes, this is a dangerous pitfall.
Always check a pointer before you dereference it. In C, you could usually count on a crash at the point where you dereference a bad pointer; in C++, you can create an invalid reference which will crash at a spot far removed from the source of the problem.
class SomeClass
{
...
void DoSomething()
{
++counter; // crash here!
}
int counter;
};
void Foo(SomeClass & ref)
{
...
ref.DoSomething(); // if DoSomething is virtual, you might crash here
...
}
void Bar(SomeClass * ptr)
{
Foo(*ptr); // if ptr is NULL, you have created an invalid reference
// which probably WILL NOT crash here
}
Forgetting an & and thereby creating a copy instead of a reference.
This happened to me twice in different ways:
One instance was in an argument list, which caused a large object to be put on the stack with the result of a stack overflow and crash of the embedded system.
I forgot the & on an instance variable, with the effect that the object was copied. After registering as a listener to the copy I wondered why I never got the callbacks from the original object.
Both where rather hard to spot, because the difference is small and hard to see, and otherwise objects and references are used syntactically in the same way.
Intention is (x == 10):
if (x = 10) {
//Do something
}
I thought I would never make this mistake myself, but I actually did it recently.
The essay/article Pointers, references and Values is very useful. It talks avoid avoiding pitfalls and good practices. You can browse the whole site too, which contains programming tips, mainly for C++.
I spent many years doing C++ development. I wrote a quick summary of problems I had with it years ago. Standards-compliant compilers are not really a problem anymore, but I suspect the other pitfalls outlined are still valid.
#include <boost/shared_ptr.hpp>
class A {
public:
void nuke() {
boost::shared_ptr<A> (this);
}
};
int main(int argc, char** argv) {
A a;
a.nuke();
return(0);
}