I am new to C++ and have been studying data structures lately. I have created linked lists in the following way:
class Random{
private:
struct Node{
int data;
Node* next;
};
}
But I came across a piece of code that is doing the same thing in the following way:
template<Typename T>
struct Listnode {
T data;
shared_ptr<ListNode<T>> next;
};
I looked it up and found that we use templates when we want to have multiple data types. Like now we can use int, double, float instead of "T". Whereas in the former case we could only use int. However, I don't understand how:
Node* next
is the same as:
shared_ptr<ListNode<T>> next
and how will these be called, I know for the former we use the:
Node->next = new Node;
Node->data = randomdata;
How does it work for the former way. Another thing of the two implementations, which one is better and why?
The T* ptr; form is the basic method declaring a pointer to a memory holding a value of type T. This kind of pointer is initialized either by the base adress of an array T[], by new T(), by new T[] or something else.
As you can see by now there are many ways to allocate the memory the pointer is pointing to. This is one of the pitfalls when it comes to freeing the memory used. should you use delete, delete[], or are we pointing to a memory not even allocated by us?
What if we forget to free the allocated memory, or try to access memory already freed?
=> with raw pointers, bugs can be occur easily!
Here smartpointers come to the rescue! Smartpointers like std::unique_ptr,
and std::shared_ptr encapsulate these raw pointers for us and handle typesafe memory management. Thus when going out of scope, the memory in a unique_ptr is automatically freed. The same is valid for shared_ptr if no references to it exists.
I would always recommend to use c++'s smart pointers where possible!
Which kind of smart pointer you should use depends on the kind of linked list you want to implement (e.g. if circular lists are supported too).
btw. have you thought about std::vector or std::list?
The second form is a type of "smart" pointer. Most code using modern c++ should be using them.
Using raw (non smart) pointers you have to remember to do the pairing of new/delete or new[]/delete[] when the object goes out of scope. In the simplistic case of a constructor/destructor its not that much of a burden. But, when you are using pointers in a function and that function throws an exception, it gets a bit tricky to free things up.
There are more than one type of smart pointer. unique, shared and weak. Uniques are for one off object that are only used in one place (like an object or function). Shared are for cases where multiple objects are using the same pointer/resource and you only want to call the allocated object's destructor when the last owner of the pointer goes out of scope. Weaks are for cases where the resource is managed by someone else and the pointed to resource should live on after the object with the weak pointer goes out of scope (they are also needed for avoiding cyclical allocations that prevent GC and cause memory leaks).
Smart pointers are a good thing, you should read up on them (Stroustrups book is great). There are few cases now were naked pointers are needed.
As Karoly Horvath said, it's not the same thing:
T* is a "plain" pointer to objects of type T, it stores an address in memory, and implicitly the type of the object that we can expect to find at this address (which is useful to know e.g. the size of the target memory).
std::shared_ptr<T> is an object that belongs to the category of "smart-pointers", which are called "smart" because they can manage the memory that is being pointed, by keeping track of how many references exist to that memory location. This means in practical terms that dynamically allocated memory will be released for you when it is no longer used by your code at runtime.
I would say that for a simple linked-list (singly or doubly linked), there is no need to use shared_ptrs. It might be useful e.g. for graphs with dynamic recurrent structure. For genericity sake though, it is better to use a templated version of your node:
template <typename T>
struct ListNode
{
T data;
ListNode<T> *next;
};
First lets get some junk out of the way:
It is good to learn and understand the raw implementations of linked lists as you will encounter them (for many good or bad reasons) in production code.
IF you ~have~ to use 'invasive' linked lists in your code, templates and 'smarter pointers' are going to save you headaches. (IMO).
You are almost always served better by collection classes/templates.
With the caveats above:
The std::shared_ptr is a 'smarter pointer' that wraps a raw pointer (typically produced by calling operator new) and adds RAII style semantics to the mix along with a contract that allows multiple holders of the underlying object to reference the content without it going away. (When used properly.)
A linked list is 'just' a convention for a program to follow (hopefully, but not required to be) homogeneous types without moving the data around. With ('old school', not bad) linked lists ALL of the link management is your responsibility. It is extra easy to either forget, or get distracted and 'forget' to free resources. This is a cause of many nights of debugging and pesky things called 'memory leaks'.
The hybrid 'template link list' is 'better' in that the resource management responsibility is reduced. It is NOT eliminated. It will help reduce a type of memory leak that is forgetting to delete an allocated node. It will NOT eliminate 'memory leaks' that are caused by circular references. (This is case where an 'external actor' is required to break the circular chain and can be extraordinarily complex in 'real' code.)
std::shared_ptr has operators defined that allow you to 'pretend' that you are interacting with WHAT the std::shared pointer is managing. In that way, visually the code looks mostly the same, but the class is(/may be) hiding a little complexity on your behalf. (Pointer checking, etc.)
Which is better? IMO neither. However given a choice between ONLY those two, I would absolutely prefer the 'smarter pointer' version over the 'manual do it your self' style in the VAST majority of cases.
If it was ME I would pick another container. However, if your intent is to learn about the fundamentals of how those containers are implemented (a good thing!) this isn't exactly the answer you want to hear. :-)
Related
This is the header of my generic binary search tree. For now I'm just using a raw pointer for the root of the tree. What kind of pointer should I use? Some of the types are unique,shared,(smart pointers) weak , and raw and on and on. . . . .
template <typename T>
class BST
{
public:
BST();
BSTNode<T>* Root;
void Insert(BSTNode<T> newNode);
void Delete(T deleteNode);
BSTNode<T>* ReturnNodeSearch();
BSTNode<T>* MinimumValue();
BSTNode<T>* MaximumValue();
bool isEmpty();
};
Use a std::unique_ptr as it is very unlikely you want two separate BST objects to share the same implementation nodes. Usually, in that case, you would just use an external reference or (possibly) an external std::shared_ptr to the BST object itself.
It just depends on what you want to do. I would suggest that best practice would be to use either std::unique_ptr<> or std::shared_ptr<> to make sure the memory is properly released when no longer needed. However, a raw pointer can work here, although you will have to handle the deallocation by yourself. In general, the benefits of smart pointers for handling and owning dynamically allocated memory tend to outweigh the benefits of using raw pointers.
In more detail but at a high level:
Raw pointer -- handles the problem but you just have to manage deallocation if you no longer need this memory anymore. You could accidentally deallocate the memory in one object/function when some other object still has a pointer to it
std::unique_ptr<> -- will manage the memory over its lifetime, good if you don't have to share the pointer with any other object
std::shared_ptr<> -- also will manage the memory, adds a bit of overhead by reference counting how many std::shared_ptr<>s also are watching the memory location. This will also make sure the memory is only removed once no other std::shared_ptr<> object is pointing to it
std::weak_ptr<> -- can only be used in combination with std::shared_ptr<>, used to prevent reference cycles for the same object in memory
There isn't necessarily a wrong answer. It just depends on your desired implementation. The only type you should never use is std::auto_ptr<>, so avoid that type.
When looking at your code sample there are 3 options that come to mind where any of them could be viable options; let's explore these options below.
Raw pointer
shared_ptr<T>
unique_ptr<T>
Each of these have their own cons & pros in their usage.
Since you are using raw in your example; I'll start with that one first:
raw
Pro: - You have the flexibility to manage the memory your self, but it comes at the cost of a higher responsibility.
Con: - It is prone to memory leaks, dangling & invalid pointers.
shared_ptr
Pro: - Manages the memory for you; and is accessible across multiple objects as it is shared memory via reference counting.
Con: - It is based on the assumption that you will never face a memory leak or dangling pointer just because of using this smart pointer where it is not always guaranteed to be released but usually is in most cases. Sometimes you may not want a pointer to be accessible across multiple objects. It also has a small performance hit from reference counting.
unique_ptr
Pro: - Nearly same as above only that one object can own this providing more protection of unwanted access.
Con: - Similar as above under the assumption that the memory will always be freed. If the functionality needed does require multiple objects or sources to access this at some future point in time, then you are limited by using this type of pointer. You can transfer ownership but you can not access via multiple objects.
In the end it comes down to your particular need of which type you will want to use. In your particular situation there is nothing wrong with using raw pointers within the class if they are private members but you have more work to manage the class and more to be conscience of when dealing with the allocation & releasing of memory. If using unique_ptr then it is a matter of knowing if the memory object will be strictly internal to the pertaining class object or not. If using shared_ptr then it is a matter of knowing which external objects will be referencing it.
In the end you had asked:
What kind of pointer should I use?
Taking the knowledge from the above information and by understanding the type of object you are working with, let's consider what the BST does or is responsible for and its primary role as a class object.
We know that it is a Binary Space Partitioning Tree typically used with a Binary Search. Where one is the data structure and the other is the searching algorithm.
It is a tree that consists of a set of nodes and each node has 2 leaf nodes. The very first node in the tree is typically called the root or the head where a leaf node that has no data or is empty a terminating node is normally called the tail and is usually set to null or nullptr. We can see the relationship of these nodes and know that the BST will have ownership of at least the root node. This way each instance of a BST object will be unique from another. Example:
BST tree1; // Tree 1
BST tree2; // Tree 2
// Not valid code below but shown to illustrate a concept
tree1.root != tree2.root; // These two roots are not equal as in not the same memory.
This is what we would want to keep one tree unique from another and because of this behavior we really wouldn't want to use shared_ptr. With this particular class I think the better option here if not using raw pointers and managing your own memory and using smart pointers to show ownership and uniqueness between multiple objects that unique_ptr would then be the one to choose.
When designing classes and trying to decide which smart pointer to use these are the basic questions you should ask & answer yourself:
Does this object have a? If yes; does it solely own it or does each instance's internal memory need to be unique? If Yes; then use a unique_ptr
Does this object have to be referenced across multiple objects? If yes, then use shared_ptr.
Here are a few references: One from a paper and another from and Q/A, one from code review:
BST-SmartPointers.pdf
Stack Overflow: unique instead of shared in BST
Stack Code Review: BST w/ Smart Pointers
These references may also help you into making a well defined decision.
I'm starting with the assumption that, generally, it is a good idea to allocate small objects in the stack, and big objects in dynamic memory. Another assumption is that I'm possibly confused while trying to learn about memory, STL containers and smart pointers.
Consider the following example, where I have an object that is necessarily allocated in the free store through a smart pointer, and I can rely on clients getting said object from a factory, for instance. This object contains some data that is specifically allocated using an STL container, which happens to be a std::vector. In one case, this data vector itself is dynamically allocated using some smart pointer, and in the other situation I just don't use a smart pointer.
Is there any practical difference between design A and design B, described below?
Situation A:
class SomeClass{
public:
SomeClass(){ /* initialize some potentially big STL container */ }
private:
std::vector<double> dataVector_;
};
Situation B:
class SomeOtherClass{
public:
SomeOtherClass() { /* initialize some potentially big STL container,
but is it allocated in any different way? */ }
private:
std::unique_ptr<std::vector<double>> pDataVector_;
};
Some factory functions.
std::unique_ptr<SomeClass> someClassFactory(){
return std::make_unique<SomeClass>();
}
std::unique_ptr<SomeOtherClass> someOtherClassFactory(){
return std::make_unique<SomeOtherClass>();
}
Use case:
int main(){
//in my case I can reliably assume that objects themselves
//are going to always be allocated in dynamic memory
auto pSomeClassObject(someClassFactory());
auto pSomeOtherClassObject(someOtherClassFactory());
return 0;
}
I would expect that both design choices have the same outcome, but do they?
Is there any advantage or disadvantage for choosing A or B? Specifically, should I generally choose design A because it's simpler or are there more considerations? Is B morally wrong because it can dangle for a std::vector?
tl;dr : Is it wrong to have a smart pointer pointing to a STL container?
edit:
The related answers pointed to useful additional information for someone as confused as myself.
Usage of objects or pointers to objects as class members and memory allocation
and Class members that are objects - Pointers or not? C++
And changing some google keywords lead me to When vectors are allocated, do they use memory on the heap or the stack?
std::unique_ptr<std::vector<double>> is slower, takes more memory, and the only advantage is that it contains an additional possible state: "vector doesn't exist". However, if you care about that state, use boost::optional<std::vector> instead. You should almost never have a heap-allocated container, and definitely never use a unique_ptr. It actually works fine, no "dangling", it's just pointlessly slow.
Using std::unique_ptr here is just wasteful unless your goal is a compiler firewall (basically hiding the compile-time dependency to vector, but then you'd need a forward declaration to standard containers).
You're adding an indirection but, more importantly, the full contents of SomeClass turns into 3 separate memory blocks to load when accessing the contents (SomeClass merged with/containing unique_ptr's block pointing to std::vector's block pointing to its element array). In addition you're paying one extra superfluous level of heap overhead.
Now you might start imagining scenarios where an indirection is helpful to the vector, like maybe you can shallow move/swap the unique_ptrs between two SomeClass instances. Yes, but vector already provides that without a unique_ptr wrapper on top. And it already has states like empty that you can reuse for some concept of validity/nilness.
Remember that variable-sized containers themselves are small objects, not big ones, pointing to potentially big blocks. vector isn't big, its dynamic contents can be. The idea of adding indirections for big objects isn't a bad rule of thumb, but vector is not a big object. With move semantics in place, it's worth thinking of it more like a little memory block pointing to a big one that can be shallow copied and swapped cheaply. Before move semantics, there were more reasons to think of something like std::vector as one indivisibly large object (though its contents were always swappable), but now it's worth thinking of it more like a little handle pointing to big, dynamic contents.
Some common reasons to introduce an indirection through something like unique_ptr is:
Abstraction & hiding. If you're trying to abstract or hide the concrete definition of some type/subtype, Foo, then this is where you need the indirection so that its handle can be captured (or potentially even used with abstraction) by those who don't know exactly what Foo is.
To allow a big, contiguous 1-block-type object to be passed around from owner to owner without invoking a copy or invalidating references/pointers (iterators included) to it or its contents.
A hasty kind of reason that's wasteful but sometimes useful in a deadline rush is to simply introduce a validity/null state to something that doesn't inherently have it.
Occasionally it's useful as an optimization to hoist out certain less frequently-accessed, larger members of an object so that its commonly-accessed elements fit more snugly (and perhaps with adjacent objects) in a cache line. There unique_ptr can let you split apart that object's memory layout while still conforming to RAII.
Now wrapping a shared_ptr on top of a standard container might have more legitimate applications if you have a container that can actually be owned (sensibly) by more than one owner. With unique_ptr, only one owner can possess the object at a time, and standard containers already let you swap and move each other's internal guts (the big, dynamic parts). So there's very little reason I can think of to wrap a standard container directly with a unique_ptr, as it's already somewhat like a smart pointer to a dynamic array (but with more functionality to work with that dynamic data, including deep copying it if desired).
And if we talk about non-standard containers, like say you're working with a third party library that provides some data structures whose contents can get very large but they fail to provide those cheap, non-invalidating move/swap semantics, then you might superficially wrap it around a unique_ptr, exchanging some creation/access/destruction overhead to get those cheap move/swap semantics back as a workaround. For the standard containers, no such workaround is needed.
I agree with #MooingDuck; I don't think using std::unique_ptr has any compelling advantages. However, I could see a use case for std::shared_ptr if the member data is very large and the class is going to support COW (copy-on-write) semantics (or any other use case where the data is shared across multiple instances).
Ok, so everyone knows that raw pointers should be avoided like the plague and to prefer smart pointers, but does this advice apply when implementing a container? This is what I am trying to accomplish:
template<typename T> class AVLTreeNode {
public:
T data;
unique_ptr<AVLTreeNode<T>> left, right;
int height;
}
Unique_ptr can make container functions more cumbersome to write because I can't have multiple raw pointers temporarily pointing to the same object in a way that is elegant. For example:
unique_ptr<AVLTreeNode<T>> rotate_right(unique_ptr<AVLTreeNode<T>> n1)
{
unique_ptr<AVLTreeNode<T>> n2 = n1->left;
n1->left = n2->right;
n2->right = n1;
// n1 must now be referenced through the longer name n2->right from now on
n2->right->recalculate_height();
n2->recalculate_height();
return n2;
}
(It's not a big deal in this example but I can imagine how it could become a problem). Should I take problems like these as a strong hint that containers should be implemented with good old new, delete, and raw pointers? It seems like awfully a lot of trouble just to avoid writing a destructor.
I do not usually use smart pointers when implementing containers as you show. Raw pointers (imho) are not to be avoided like the plague. Use a smart pointer when you want to enforce memory ownership. But typically in a container, the container owns the memory pointed to by the pointers making up the data structure.
If in your design, an AVLTreeNode uniquely owns its left and right children and you want to express that with unique_ptr, that's fine. But if you would prefer that AVLTree owns all AVLTreeNodes, and does so with raw pointers, that is just as valid (and is the way I usually code it).
Trust me, I'm not anti-smart-pointer. I am the one who invented unique_ptr. But unique_ptr is just another tool in the tool box. Having good smart pointers in the tool box is not a cure-all, and using them blindly for everything is not a substitute for careful design.
Update to respond to comment (comment box was too small):
I use raw pointers a lot (which are rarely owning). A good sampling of my coding style exists in the open source project libc++. One can browse the source under the "Browse SVN" link.
I prefer that every allocation of a resource be deallocate-able in a destructor somewhere, because of exception safety concerns, even if the usual deallocation happens outside of a destructor. When the allocation is owned by a single pointer, a smart pointer is typically the most convenient tool in the tool box. When the allocation is owned by something larger than a pointer (e.g. a container, or a class Employee), raw pointers are often a convenient part of the data structure composing the larger object.
The most important thing is that I never allocate any resource without knowing what object owns that resource, be it smart pointer, container, or whatever.
The code you presented compiles with no problems
#include <memory>
template<typename T> class AVLTreeNode {
public:
T data;
std::unique_ptr<AVLTreeNode<T>> left, right;
int height;
};
int main()
{
AVLTreeNode<int> node;
}
test compilation: https://ideone.com/aUAHs
Personally, I've been using smart pointers for trees even when the only thing we had was std::auto_ptr
As for rotate_right, it could be implemented with a couple calls to unique_ptr::swap
Small correction: raw pointers should not be avoided like the plague (oops, not everybody knew the fact), but manual memory management should be avoided when possible (by using containers instead of dynamic array or smartpointers), so in your function, just do a get() on your unique_ptr for temporary storage.
std::shared_ptr does not have these restrictions. Especially, multiple shared_ptr-instances can reference the same object.
Herb Shutter has very clear guideline about not using shared_ptr as parameters in his GoTW series:
Guideline: Don’t pass a smart pointer as a function parameter unless
you want to use or manipulate the smart pointer itself, such as to
share or transfer ownership.
and this...
Guideline: Prefer passing objects by value, *, or &, not by smart
pointer.
I am pretty proficient with C, and freeing memory in C is a must.
However, I'm starting my first C++ project, and I've heard some things about how you don't need to free memory, by using shared pointers and other things.
Where should I read about this? Is this a valuable replacement for proper delete C++ functionality? How does it work?
EDIT
I'm confused, some people are saying that I should allocate using new and use smart pointers for the deallocation process.
Other people are saying that I shouldn't allocate dynamic memory in the first place.
Others are saying that if I use new I also have to use delete just like C.
So which method is considered more standard and more-often used?
Where should I read about this?
Herb Sutter's Exceptional C++ and Scott Meyers's More Effective C++ are both excellent books that cover the subject in detail.
There is also a lot of discussion on the web (Google or StackOverflow searches for "RAII" or "smart pointer" will no doubt yield many good results).
Is this a valuable replacement for proper delete C++ functionality?
Absolutely. The ability not to worry about cleaning up resources, especially when an exception is thrown, is one of the most valuable aspects of using RAII and smart pointers.
What I meant in my comment (sorry for being terse - I had to run out to the shops) is that you should be using:
std::string s = "foobar";
rather than:
std::string * s = new std::string( "foobar" );
...
delete s;
and:
vector <Person> p;
p.push_back( Person( "fred" ) );
rather than:
vector <Person *> p;
p.push_back( new Person( "fred" ) );
You should always be using classes that manage memory for you. In C++ the main reason for creating an object using new is that you don't know its type at compile-time. If that isn't the reason, think long and hard before using new and delete, or even smart pointers.
If you allocate dynamic memory (with new), you need to free it (with delete), just like using malloc/free in C. The power of C++ is that it gives you lots of ways of NOT calling new, in which case you don't need to call delete.
You still have to worry about freeing memory in C++, it's just that there are better methods/tools for doing so. One can argue that attention to memory management in C++ is more difficult as well due to the added requirement of writing exception safe code. This makes things such as:
MyClass *y = new MyClass;
doSomething(y);
delete y;
Look completely harmless until you find that doSomething() throws an exception and now you have a memory leak. This becomes even more dangerous as code is maintained as the code above could have been safe prior to someone changing the doSomething() function in a later release.
Following the RAII methodology is a big part of fixing memory management challenges and using auto_ptr's or shared pointers provided by libraries such as Boost make it easier to incorporate these methods into your code.
Note that auto_ptr is not a "shared" pointer. It is an object that takes ownership of the dynamically allocated object and gives that ownership away on assignment and copy. It doesn't count references to the memory. This makes it unsuitable for use within standard containers and many in general prefer the shared_ptr of Boost to the auto_ptr provided by the standard.
It is never safe to put auto_ptrs into
standard containers. Some people will
tell you that their compiler and
library compiles this fine, and others
will tell you that they've seen
exactly this example recommended in
the documentation of a certain popular
compiler; don't listen to them.
The problem is that auto_ptr does not
quite meet the requirements of a type
you can put into containers, because
copies of auto_ptrs are not
equivalent. For one thing, there's
nothing that says a vector can't just
decide to up and make an "extra"
internal copy of some object it
contains. For another, when you call
generic functions that will copy
elements, like sort() does, the
functions have to be able to assume
that copies are going to be
equivalent. At least one popular sort
internally takes a copy of a "pivot"
element, and if you try to make it
work on auto_ptrs it will merrily take
a copy of the pivot auto_ptr object
(thereby taking ownership and putting
it in a temporary auto_ptr on the
side), do the rest of its work on the
sequence (including taking further
copies of the now-non-owning auto_ptr
that was picked as a pivot value), and
when the sort is over the pivot is
destroyed and you have a problem: At
least one auto_ptr in the sequence
(the one that was the pivot value) no
longer owns the pointer it once held,
and in fact the pointer it held has
already been deleted!
Taken From: Using auto_ptr Effectively
Well, of course you need to delete. I would rephrase this as 'what libraries can I use that can automate the deletion of allocated memory?'. I'd recommend you start by reading up the Boost Smart pointers page.
The best answer I can give you is: something needs to call delete for each object created with new. Whether you do it manually, or using a scope-based smart pointer, or a reference-counted smart pointer, or even a non-deterministic garbage collector, it still needs to be done.
Having said that, I have not manually called delete in 10 years or so. Whenever I can I create an automatic object (on the stack); when I need to create an object on the heap for some reason I try using a scope-based smart pointer, and in rare cases when there is a legitimate reason to have shared ownership, I use a reference counted smart pointer.
This is a great question, and actually several in one:
Do I need to worry about Managing Memory?
Yes! There is no garbage collection in C++. Anytime you allocate something with new you need to either call delete in your own code, or delegate that responsibility to something like a smart pointer.
When Should I use dynamic memory allocation?
The reasons you'd want to use dynamic memory allocation (allocating with new). Some of these include:
You don't know the size of the thing you are allocating at compile time
You don't know the type of the thing you are allocating at compile time
You are reusing the same data in different contexts and don't want to pay the performance overhead of copying that data around.
There are lots of other reasons, and these are gross over generalizations, but you get the idea.
What tools can I use to help me with memory management?
Smart pointers are the way to go here. A smart pointer will take ownership of memory that you allocate, and then release that memory automatically for you at a specific time depending on the policy the smart pointer.
For example, a boost::scoped_ptr will deallocate memory for you when it goes out of scope
{
scoped_ptr<MyClass> myVar( new MyClass() );
// do Something with myVar
} // myVar goes out of scope and calls delete on its MyClass
In general you should use smart pointers over raw pointers anytime you can. It will save you years of tracking down memory leaks.
Smart pointers come in many forms including:
std::auto_ptr
Boost Smart Pointers
If you can use Boost smart pointers I would. They rock!
Since C++ does not have a garbage collector built into the language, you need to be aware of what memory you have dynamically allocated and how that memory is being freed.
That said, you can use smart pointers to alleviate the problem of having to manually free memory via delete - for example, see Smart Ponters (boost).
First and foremost, before you get into the business of using auto_ptr's and writing your own RAII classes, learn to use the Standard Template Library. It provides many common container classes that automatically allocate their internal memory when you instantiate them and free it up when they go out of scope - things like vectors, lists, maps, and so forth. When you employ STL, using the new-operator and delete (or malloc and free) is rarely necessary.
Freeing memory in C++ is just as much a must as in C.
What you may be thinking of is a smart pointer library (the standard library's auto_ptr among others) - which will do reference counting for you.
'm confused, some people are saying
that I should allocate using new and
use smart pointers for the
deallocation process.
They're right. Just like in C you still need to manage all your memory one way or another. however there are ways to use the language to automate delete.
Smart pointers are basically local scope wrappers for pointers which use the object .dtor to delete the corresponding pointer once the smart pointer - which is like any other objecton the stack - goes out of scope
The beauty of C++ is that you have explicit control over when things are created and when things are destroyed. Do it right and you will not have issues with memory leaks etc.
Depending on your environment, you may want to create objects on the stack or you may want to dynamically allocated (create them on the 'heap' - heap in quotes because its an overused term but is good enough for now).
Foo x; // created on the stack - automatically destroyed when the program exits that block of code it was created in.
Foo *y = new Foo; // created on the heap - its O.K. to pass this one around since you control when its destroyed
Whenever you use 'new', you should use the corresponding version of delete... somewhere, somehow. If you use new to initialize a smart pointer like:
std::auto_ptr x = new Foo;
You are actually creating two items. An instance of auto_ptr and an instance of Foo. auto_ptr is created on the stack, Foo on the heap.
When the stack 'unwinds', it will automatically call delete on that instance of Foo. Automatically cleaning it up for you.
So, general rule of thumb, use the stack version whenever possible/practical. In most instances it will be faster as well.
In order of preference, you should:
Avoid handling allocation yourself at all. C++'s STL (standard template library) comes with a lot of containers that handle allocation for you. Use vector instead of dynamically allocated arrays. Use string instead of char * for arrays of characters. Try to seek out an appropriate container from the STL rather than designing your own.
If you are designing your own class and honestly need dynamic allocation (and you usually won't if you compose your class using members of the STL), place all instances of new (new[]) in your constructor and all instances of delete (delete[]) in your destructor. You shouldn't need malloc and free, generally.
If you are unable to keep your allocations paired within constructors and destructors, use smart pointers. Really this is not so different from #2; smart pointers are basically just special classes which use destructors to ensure deallocation happens.
I'm curious as I begin to adopt more of the boost idioms and what appears to be best practices I wonder at what point does my c++ even remotely look like the c++ of yesteryear, often found in typical examples and in the minds of those who've not been introduced to "Modern C++"?
I don't use shared_ptr almost at all, because I avoid shared ownership in general. Therefore, I use something like boost::scoped_ptr to "own" an object, but all other references to it will be raw pointers. Example:
boost::scoped_ptr<SomeType> my_object(new SomeType);
some_function(my_object.get());
But some_function will deal with a raw pointer:
void some_function(SomeType* some_obj)
{
assert (some_obj);
some_obj->whatever();
}
Just a few off the top of my head:
Navigating around in memory-mapped files.
Windows API calls where you have to over-allocate (like a LPBITMAPINFOHEADER).
Any code where you're munging around in arbitrary memory (VirtualQuery() and the like).
Just about any time you're using reinterpret_cast<> on a pointer.
Any time you use placement-new.
The common thread here is "any situation in which you need to treat a piece of memory as something other than a resource over which you have allocation control".
These days I've pretty much abandoned all use of raw pointers. I've even started looking through our code base for places where raw pointers were used and switched them to a smart pointer variant. It's amazing how much code I've been able to delete by doing this simple act. There is so much code wasted on lifetime management of raw C++ pointers.
The only places where I don't use pointers is for a couple of interop scenarios with other code bases I don't have control over.
I find the primary difference between 'modern' C++ and the old* stuff is careful use of class invariants and encapsulation. Well organised code tends naturally to have fewer pointers flying around. I'm almost as nervous swimming in shared_ptrs as I would be in news and deletes.
I'm looking forward to unique_ptr in C++0x. I think that will tidy away the few (smart) pointers that do still roam the wild.
*still unfortunately very common
Certainly any time you're dealing with a legacy library or API you'll need to pass a raw pointer, although you'll probably just extract it from your smart pointer temporarily.
In fact it is always safe to pass a raw pointer to a function, as long as the function does not try to keep a copy of the pointer in a global or member variable, or try to delete it. With these restrictions in place, the function cannot affect the lifetime of the object, and the only reason for a smart pointer is to manage the object lifetime.
I still use regular pointers in resource-sensitive code or other code that needs tiny footprint, such as certain exceptions, where I cannot assume that any data is valid and must also assume that I am running out of memory too.
Managed memory is almost always superior to raw otherwise, because it means that you don't have to deal with deleting it at the right place, but still have great control over the construction and destruction points of your pointers.
Oh, and there's one other place to use raw pointers:
boost::shared_ptr<int> ptr(new int);
I still use raw pointers on devices that have memory mapped IO, such as embedded systems, where having a smart pointer doesn't really make sense because you will never need or be able to delete it.
If you have circular data structures, e.g., A points to B and B points back to A, you can't use naively use smart pointers for both A and B, since then the objects will only be freed extra work. To free the memory, you have to manually clear the smart pointers, which is about as bad as the delete the smart pointers get rid of.
You might thing this doesn't happen very often, but suppose you have Parent object that has smart pointers to a bunch of Child objects. Somewhere along the way someone needs to look up a the Parent for a Child, so they add a smart pointer member to Child that points back to the parent. Silently, memory is no longer freed.
Some care is required. Smart pointers are not equivalent to garbage collection.
I'm writing C++ that has to co-exist with Objective C (using Objective C++ to bridge).
Because C++ objects declared as part of Objective C++ classes don't have constructors or destructors called you can't really hold them there in smart pointers.
So I tend to use raw pointers, although often with boost::intrustive_ptr and an internal ref count.
Not that I would do it, but you need raw pointers to implement, say, a linked list or a graph. But it would be much smarter to use std::list<> or boost::graph<>.