I have a generic linked list that works with various types of data including objects and pointers to objects, etc, but i'm having trouble working with the list when I insert objects from a class that is derived from an abstract class.
I have an abstract class called vehicle and 2 classes that are carr and truck and I can do something like this:
list<vehicle> lv;
vehicle * v1;
vehicle * v2;
v1 = new carr;
v2 = new truck;
cin >> *v1 >> *v2;
//But when I try to insert in the list
lv.insertEnd(*v1);
I have the error:
cannot allocate an object of abstract type 'vehicle'
And the compiler show that the error is in the insertEnd method of my linked list code in the part where I write:
newNode->item = new Item;
This a part of a project where I need to have a list of vehicles and the vehicles can be carrs, trucks, etc. I have the group of vehicles implemented with pointers to pointers but i'm trying to do this with a list of vehicles.
Can you help me?
EDIT:
The item is in my linked list, i'll show my insertEnd method:
template <class Item>
void list<Item>::insertEnd(const Item& item)
{
node<Item> *newNode= new node<Item>;
newNode->item = new Item;
*(newNode->item) = item;
newNode->next = 0;
if(head == 0)
{
head = newNode;
tail = newNode;
_size++;
}
else
{
novoNo->prev = tail;
tail->next = newNode;
tail = newNode;
_size++;
}
}
You are trying to store an item by value in your linked list. Using items by value breaks polymorphism: only pointers or references are polymorphic.
The reason this is the error you see is that you are dereferencing your pointer here: lv.insertEnd(*v1). Passing in a value this way will cause C++ to use the copy constructor for the type specified in insertEnd to make the object inside of your insertEnd function (check your code: the type of the parameter to insertEnd is surely the type specified in your template - which is vehicle here). By passing by value, you are telling your code to copy the whole of v1 into a new object inside of insertEnd. This falls apart, because vehicle is an abstract class: its copy constructor cannot be used to make a fully functional object, because it's abstract.
This sort of shadows what's really going on here: you can't pass around objects by value and expect them to be polymorphic. If you don't see this error, what will likely happen is that you will likely slice your object, which can be even worse to debug. Do what #billz recommends and use a smart pointer.
EDIT: after seeing your addition of your insertEnd code, where you are passing by reference, there is an addendum: the compiler is not going to call the copy constructor in insertEnd. Instead, you likely see the error on this line: newNode->item = new Item. Here you can see where you are trying to instantiate the abstract class. Replace the word 'Item' with 'vehicle' - that's what you're doing with your template - and you can see it very clearly.
In any case, passing-by-reference to a dereferenced pointer is a very painful and error-prone thing indeed. It's way too easy to introduce errors: if you delete v1 anywhere in your code, like a good programmer does (great ones use auto pointers), you are likely to leave your reference dangling: pointing to a space in memory that someday - like when someone important is running your code - may be filled with garbage without your reference knowing it. This be the way to madness, my friend.
This is exactly why smart pointers are a C++ programmer's best friend: once you understand what they're doing, you can all but ignore this sort of mess and just pass them around by value freely. Their lifecycle contract is very well defined, they clean up after themselves, they are exception safe. As long as you don't set up reference cycles - which is far less problematic in everyday usage than passing a dereferenced pointer by reference - or try to use auto_ptr in a standard container PLEASE READ THIS LINK AND UNDERSTAND IT, you've vastly reduced your memory problems.
you need to use pointer in this case, the better way is to use smart pointer.
std::list<std::shared_ptr<vehicle> > lv;
In your list<vehicle> lv;, lv only contains vehicle type object, lv.insertEnd(*v1); will slice your object to vehicle type which is not allow as vehicle is abstract class.
since one cannot instantiate an object of abstract types, it failed to construct the object for insertion.
Also, the copy construction semantics of stl does not support polymorphic use. a "vehicle" list should only contain vehicle objects, not car objects.
You have to use container of pointers.
Related
Can we implement a link list without using the head pointer means by using a simple variable of the head instead of the pointer of the head ?
Yes. If you are implementing a circular linked list with a sentinel node, the sentinel node can be the simple variable that also serves as the head.
Alternatively, you could use a std::optional instance to serve as the head.
In specific cases you could, but in general not. And why would you want to? Here are some reasons, I could think of now. Take for example this code:
template<class T>
class Node
{
private:
T value;
Node<T> *next;
};
class MyLinkedList
{
private:
bool isEmpty; // indicates wether the list is empty or not
Node head; // Head as member
};
But there are several major flaws with this code:
You would always need to care about isEmpty when adding or deleting, or doing anything with the list
You can't initialize head if T has no default constructor
When deleting the last element you have to call the destructor of object that technically remains in scope.
When deleting the last element and then deleting the empty list the destructor of Node::value will be called twice
Don't know if those are all reasons, but I think, just #2 is a big enough problem to not consider this.
Of course you could use std::optional, but that's just a pointer with a wrapper. which even works, without a default constructor, so could be an alternative. Alltough it would be used in the same way as a (smart) pointer, so it's not "a simple variable of the head".
I have only been using raw pointers for linked list with templates. For example, the member data, Node<T>* head; and when I am inserting a node one of the lines would be head = new Node<T>(data);.
However, now I need to use a smart pointer and I am not sure how I would change it to use smart pointers. Would the member data be changed to shared_ptr<Node<T>> head; and the other line would change to
head = shared_ptr<Node<T>>( new <Node<T>>(data) );?
You do not "need" to use a smart pointer for a linked list, because that statement doesn't make sense. You do not use smart pointers for low-level data structures. You use smart pointers for high-level program logic.
As far as low-level data structures are concerned, you use a standard container class from the C++ standard library, like std::list [*], which solves all your memory-management problems anyway, without using any smart pointers internally.
If you really really need your own highly specialised/optimised custom container class because the entire C++ standard library is unfit for your requirements and you need a replacement for std::list, std::vector, std::unordered_map and other optimised, tested, documented and safe containers – which I very much doubt! –, then you have to manage memory manually anyway, because the point of such a specialised class will almost certainly be the need for techniques like memory pools, copy-on-write or even garbage collection, all of which conflict with a typical smart pointer's rather simplistic deletion logic.
In the words of Herb Sutter:
Never use owning raw pointers and delete, except in rare cases when
implementing your own low-level data structure (and even then keep
that well encapsulated inside a class boundary).
Something along those lines is also expressed in Herb Sutter's and Bjarne Stroustrup's C++ Core Guidelines:
This problem cannot be solved (at scale) by transforming all owning
pointers to unique_ptrs and shared_ptrs, partly because we need/use
owning "raw pointers" as well as simple pointers in the implementation
of our fundamental resource handles. For example, common vector
implementations have one owning pointer and two non-owning pointers.
Writing a linked-list class in C++ with raw pointers can be a useful academic exercise. Writing a linked-list class in C++ with smart pointers is a pointless academic exercise. Using any of these two self-made things in production code is almost automatically wrong.
[*] Or just std::vector, because due to cache locality that will almost always be the better choice anyway.
There are basically two alternatives to set up a smart-pointer enhanced list:
Using std::unique_ptr:
template<typename T>
struct Node
{
Node* _prev;
std::unique_ptr<Node> _next;
T data;
};
std::unique_ptr<Node<T> > root; //inside list
That would be my first choice. The unique-pointer _next takes care there are no memory leaks, whereas _prev is an observing pointer. However, copy constructor and such things -- in case you need them -- need to be defined and implemented by hand.
Using shared_ptr:
template<typename T>
struct Node
{
std::weak_ptr<Node> _prev; //or as well Node*
std::shared_ptr<Node> _next;
T data;
};
std::shared_ptr<Node<T> > root; //inside list
This is alternative is copyable by design and adds further safety because of the weak_ptr, see below. It is less performant than the unique_ptr when it comes to structural changes of the list, such as insertions and removals, e.g. due to thread safety in shared_ptr's control block.
Yet, traversing the list, i.e. dereferencing the pointers, should be as performant as for the unique_ptr.
In both approaches the idea is that one node owns the complete remaining list. Now when a node goes out of scope, there is no danger that the remaining list becomes a memory leak, as the nodes are iteratively destructed (starting from the last one).
The _prev pointer is in both options only an observing pointer: it's task is not to keep the previous nodes alive, but only to provide a link to visit them.
For that, a Node * is usually sufficient (--note: observing pointer means you never do memory related stuff like new, delete on the pointer).
If you want more safety, you can also use a std::weak_ptr which prevents from things like
std::shared_ptr<Node<T> > n;
{
list<T> li;
//fill the list
n = li.root->next->next; //let's say that works for this example
}
n->_prev; //dangling pointer, the previous list does not exists anymore
Using a weak_ptr, you can lock() it and in this way chack whether _prev is still valid.
I would look at the interface of std::list, which is a C++ implementation of linked lists. It seems that you are approaching the templating of your Linked list class wrong. Ideally your linked list should not care about ownership semantics (i.e. whether it is instantiated with raw ptrs, smart pointers or stack allocated variables). An example of ownership sematics with STL containers follows. However, there are better examples of STL and ownership from more authoritative sources.
#include <iostream>
#include <list>
#include <memory>
using namespace std;
int main()
{
// Unique ownership.
unique_ptr<int> int_ptr = make_unique<int>(5);
{
// list of uniquely owned integers.
list<unique_ptr<int>> list_unique_integers;
// Transfer of ownership from my parent stack frame to the
// unique_ptr list.
list_unique_integers.push_back(move(int_ptr));
} // list is destroyed and the integers it owns.
// Accessing the integer here is not a good idea.
// cout << *int_ptr << endl;
// You can make a new one though.
int_ptr.reset(new int(6));
// Shared ownership.
// Create a pointer we intend to share.
shared_ptr<int> a_shared_int = make_shared<int>(5);
{
// A list that shares ownership of integers with anyone that has
// copied the shared pointer.
list<shared_ptr<int>> list_shared_integers;
list_shared_integers.push_back(a_shared_int);
// Editing and reading obviously works.
const shared_ptr<int> a_ref_to_int = list_shared_integers.back();
(*a_ref_to_int)++;
cout << *a_ref_to_int << endl;
} // list_shared_integers goes out of scope, but the integer is not as a
// "reference" to it still exists.
// a_shared_int is still accessible.
(*a_shared_int)++;
cout << (*a_shared_int) << endl;
} // now the integer is deallocated because the shared_ptr goes
// out of scope.
A good exercise to understand ownership, memory allocation/deallocation, and shared pointers is to do a tutorial where you implement your own smart pointers. Then you will understand exactly how to use smart pointers and you will have one of those xen moments where you realise how pretty much everything in C++ comes back to RAII (ownership of resources).
So back to the crux of your question. If you want to stick to Nodes of type T, don't wrap the node in a smart pointer. The Node destructor must delete the underlying raw pointer. The raw pointer may point to a smart pointer itself specified as T. When your "LinkedList"'s class destructor is called it iterates through all Nodes with Node::next and calls delete node; after it obtained the pointer to the next node.
You could create a list where nodes are smart pointers... but this is a very specialised linked list probably called SharedLinkedList or UniqueLinkedList with very different sematics for object creation, popping, etc. Just as an example, a UniqueLinkedList would move a node in the return value when popping a value to a caller. To do metaprogramming for this problem would require the use of partial specialization for different types of T passed. Example, something like:
template<class T>
struct LinkedList
{
Node<T> *head;
};
// The very start of a LinkedList with shared ownership. In all your access
// methods, etc... you will be returning copies of the appropriate pointer,
// therefore creating another reference to the underlying data.
template<class T>
struct LinkedList<std::shared_ptr<T>>
{
shared_ptr<Node<T>> head;
};
Now you start implementing your own STL! You can already see potential for problems as mentioned in the comments to your question with this approach. If nodes have shared_ptr next it will result in a call to that shared Node's destructor, which will call the next shared Node destructor and so forth (stack overflow due to the recursion is possible). So that is why I don't care much for this approach.
Structure will look like
template<typename T> struct Node
{
T data;
shared_ptr<Node<T>> next;
};
Creating of node will look like
shared_ptr<Node<int>> head(new Node<int>);
or
auto head = make_shared<Node>(Node{ 1,nullptr });
dont use smart pointer in graph like data structure because it may cause stack overflow an many performance issue due to recursive call of destructor or inc, decr reference count wich it non optimal due to how dfs and bfs algorithm work
I'm a little confused about implementing a doubly linked list where the data in the list are pointers.
The private part of my linked list class looks like:
private:
struct node {
node* next;
node* prev;
T* o;
};
node* first; // The pointer to the first node (NULL if none)
node* last; // The pointer to the last node (NULL if none)
unsigned int size_;
As you can see, the list is full of pointers to objects rather than just plain old objects, which makes it a little more confusing to me.
The following is the description in the spec:
Note that while this list is templated across the contained type, T, it inserts and removes only pointers to T, not instances of T. This ensures that the Dlist implementation knows that it owns inserted objects, it is responsible for copying them if the list is copied, and it must destroy them if the list is destroyed.
Here is my current implementation of insertFront(T* o):
void Dlist::insertFront(T* o) {
node* insert = new node();
insert->o = new T(*o);
insert->next = first;
insert->prev = last;
first = insert;
}
This seems wrong though. What if T doesn't have a copy constructor? And how does this ensure sole ownership of the object in the list?
Could I just do:
insert->o = o;
It seems like this is not safe, because if you had:
Object* item = new Object();
dlist.insertFront(item);
delete item;
Then the item would be also be destroyed for the list. Is this correct? Is my understanding off anywhere?
Thanks for reading.
Note: While this looks like homework, it is not. I am actually a java dev just brushing up my pointer skills by doing an old school project.
When you have a container of pointers, you have one of the two following usage scenarios:
A pointer is given to the container and the container takes responsibility for deleting the pointer when the containing structure is deleted.
A pointer is given to the container but owned by the caller. The caller takes responsibility for deleting the pointer when it is no longer needed.
Number 1 above is quite straight-forward.
In the case of number 2, it is expected that the owner of the container (presumably also the caller) will remove the item from the container prior to deleting the item.
I have purposely left out a third option, which is actually the option you took in your first code example. That is to allocate a new item and copy it. The reason I left it out is because the caller can do that.
The other reason for leaving it out is that you may want a container that can take non-pointer types. Requiring it to be a pointer by always using T* instead of T may not be as flexible as you want. There are times when you should force it to be a pointer, but I can't think of any use (off the top of my head) for doing this for a container.
If you allow the user to declare Dlist<MyClass*> instead of Dlist<MyClass> then the owner of that list is implicitly aware that it is using pointers and this forces them to assume scenario Number 2 from above.
Anyway, here are your examples with some commentary:
1. Do not allocate a new T item unless you have a very good reason. That reason may simply be encapsulation. Although I mentioned above that you shouldn't do this, there are times when you may want to. If there is no copy constructor, then your class is probably plain-old-data. If copying is non-trivial, you should follow the Rule of Three.
void Dlist::insertFront(T* o) {
node* insert = new node();
insert->o = new T(*o); //<-- Follow rule of three
insert->next = first;
insert->prev = last;
first = insert;
}
2. This is what you would normally do
insert->o = o;
3. You must not delete your item after inserting. Either pass ownership to your container, or delete the item when neither you nor the container requires it anymore.
Object* item = new Object();
dlist.insertFront(item);
delete item; //<-- The item in the list is now invalid
I have a class Stack, using template, one of its methods is "push", which is written below:
template <class T>
void Stack<T>::push(T _data){
Node<T>* temp = new Node<T>;
temp->data = _data;
temp->next = head;
head = temp;
}
The stack works well with int, double, string, char....
But it says
prog.cpp:32: note: synthesized method ‘Node<Tree>::Node()’ first required here
when I use a class "Tree" as data type.
I don't understand, why it works with "string" but not with "Tree", they are both classes, not primitive types.
http://ideone.com/NMxeF
(Ignore the other error, my IDE only gives one error at line 32 and some warnings)
Help!
Edit after reading the actual code (the "note" shown above is fairly misleading about the real problem).
Looking at the code, where you try to use new Node<T>;, that needs a default constructor for T (which in this case is Tree) because your Node template contains an instance of T:
struct Node {
T data; // <--- instance of T, not being initialized in your code.
Node *next;
};
Tree doesn't have a default constructor, so that fails (and the note is showing you where the default constructor would be needed).
You have a few choices about how to fix that. The most obvious would be for a Node to hold either a pointer or a reference to a T instead of containing an actual instance of T.
Another would be to have Node's constructor take a reference to a (probably const) T, and copy that T into the Node:
class Node {
T data;
Node *next;
public:
Node(T const &dat) : data(dat), next(0) {}
};
The choice between these two approaches is fairly fundamental. If you have Node store a pointer/reference to T, then it will be the responsibility of calling code to ensure the passed object remains valid as long as the Node exists. The node and calling code will share access to a single instance of T.
By contrast, if you copy the passed object into the Node, then this copy will be destroyed when the Node is destroyed. The original T (Tree, in your case) you passed to the Node will remain the responsibility of the calling code, and the Node will take responsibility for its copy.
In the usual case, you'd tend to favor the latter -- it gives cleaner semantics, and keeps ownership of the data clear. In the case of a Tree, however, you probably don't want to copy an entire tree into a Node if you can avoid it. One compromise position would be to use something like a Node<shared_ptr<Tree> > instead. The shared_ptr can keep copying fast and cheap, while avoiding writing a Node that's only suitable for a few kinds of objects and situations. That also makes fairly explicit that you're storing only a pointer that gives shared access to the original object.
Do you have a default constructor for Tree? If not, that might be your problem: Node holds in its data member a Tree type that must be default constructed when you call new Node<Tree>.
To fix, you can modify Node's constructor to take data and next as a parameter, so you don't require default constructor on its template type (you still need assignment operator to be available).
I have general question regarding the use of pointers vs. references in this particular scenario.
Let's say that I have a function that is going to do some computation and store the value inside an object for later use by the caller. I can implement this by using either pointers or references.
Although, I would prefer using references because I trying avoiding pointers as much as possible, are there any pros/cons of one approach over the other.
The code using Pointers would be as follows:
Node*& computeNode() {
// Do some computation before creating a node object.
Node* newNode = new Node;
newNode->member1 = xyz;
newNode->member2 = abc;
// and so on ...
return newNode;
}
The code using references could do something like this:
void computeNode(Node& newNode) {
// Do some computation before assigning values to the node object.
newNode.member1 = xyz;
newNode.member2 = abc;
// and so on.
}
The differences that I can see are as follows:
When using the pointer method, the newNode object is allocated on the Heap. So, unless I call delete on it, it is not going to get deleted. However, in the reference method, whether newNode is allocated on the Heap/Stack depends on what the caller did to create the newNode object.
Whenever we use references, the number of arguments needed to pass to the function increases by at least 1. This is fine, only I find it a bit counter-intuitive to pass the return object also to a function call unless I name the function in such a way that it becomes obvious to the API user.
By using references, I can simulate the return of multiple objects. In the pointer method, I think I will have to wrap all the objects in another structure (like a pair class) and then return it. That increases the overhead.
However, I do not know if usually one is preferred over the other. And if there are any function naming conventions in C++ that let the developer know that he is supposed to pass the return object also as an argument.
You could try returning an auto_ptr or shared_ptr. That would eliminate the issues with delete.
The second approach is probably preferable because there is no possibility of a memory leak, in the event you forget to delete the returned pointer.
It's usually good practice to code in such a way that each function or object which allocates heap memory also deallocates that memory. Your first example violates that practice, making it the function caller's responsibility to deallocate the memory. This makes memory leaks more likely, because now every time the function is called there is another opportunity to forget to delete the returned pointer.
You may also want to consider returning the object by value (which will return a copy of the object) in cases where the size of the object is not that large. Even though this will require a copy to be created, if the object is not so large it won't impact performance. (This method will become a lot more attractive in the future with C++0x move semantics.)
I think your first option should be returning by value (or perhaps make the constructor compute the members?):
Node computeNode()
{
Node n;
n.x = abc;
n.y = xyz;
return n;
}
This may look inefficient, but it is quite possible that copying is elided with NRVO.
If the Node needs to be dynamically allocated anyway, you should return the pointer by value (a copy of the pointer):
Node* computeNode();
Otherwise you will be returning a reference to a local variable (pointer).
I prefer using the second approach to send back information (as you said, allows for multiple "returns" without using an extra structure) and generally return an error or a success code.
Also, I set the purely input arguments as const & to distinguish between the input and output variables.
You can return by value and avoid copies in some situations, by using const references like this :
Node computeNode() {
// Do some computation before creating a node object.
Node newNode;
newNode.member1 = xyz;
newNode.member2 = abc;
return newNode;
}
const Node &n = computeNode();
The lifetime of the temporary object in computeNode is extended upto the scope of the reference n
If the alternatives are really as given, it’s not clear why you need a reference/pointer at all; you could also just return by value:
Node computeNode() {
// Do some computation before creating a node object.
Node newNode;
newNode.member1 = xyz;
newNode.member2 = abc;
return newNode;
}
Despite what many people think, this isn’t actually very inefficient because the compiler can (and will!) elide most of the unnecessary copies.
Semantically, this is the solution that you want, unless the node gets stored somewhere else as well and you need to preserve reference identity.