This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Overriding parent class’s function
I'm struggling with calling a virtual function in C++.
I'm not experienced in C++, I mainly use C# and Java so I might have some delusions, but bear with me.
I have to write a program where I have to avoid dynamic memory allocation if possible. I have made a class called List:
template <class T> class List {
public:
T items[maxListLength];
int length;
List() {
length = 0;
}
T get(int i) const {
if (i >= 0 && i < length) {
return items[i];
} else {
throw "Out of range!";
}
};
// set the value of an already existing element
void set(int i, T p) {
if (i >= 0 && i < length) {
items[i] = p;
} else {
throw "Out of range!";
}
}
// returns the index of the element
int add(T p) {
if (length >= maxListLength) {
throw "Too many points!";
}
items[length] = p;
return length++;
}
// removes and returns the last element;
T pop() {
if (length > 0) {
return items[--length];
} else {
throw "There is no element to remove!";
}
}
};
It just makes an array of the given type, and manages the length of it.
There is no need for dynamic memory allocation, I can just write:
List<Object> objects;
MyObject obj;
objects.add(obj);
MyObject inherits form Object. Object has a virtual function which is supposed to be overridden in MyObject:
struct Object {
virtual float method(const Input& input) {
return 0.0f;
}
};
struct MyObject: public Object {
virtual float method(const Input& input) {
return 1.0f;
}
};
I get the elements as:
objects.get(0).method(asdf);
The problem is that even though the first element is a MyObject, the Object's method function is called. I'm guessing there is something wrong with storing the object in an array of Objects without dynamically allocating memory for the MyObject, but I'm not sure.
Is there a way to call MyObject's method function? How? It's supposed to be a heterogeneous collection btw, so that's why the inheritance is there in the first place.
If there is no way to call the MyObject's method function, then how should I make my list in the first place?
Also I have no access to libraries outside of math.h and stdlib.h, so vector is not available for example.
You need to store pointers in the list. Try this:
List<Object*> objects;
Object *obj1 = new Object;
MyObject *obj2 = new MyObject;
Object *obj3 = new MyObject;
objects.add(obj1);
objects.add(obj2);
objects.add(obj3);
// This calls the implementation in Object class
objects.get(0)->method(asdf);
// This calls the implementation in MyObject class
objects.get(1)->method(asdf);
// This calls the implementation in MyObject class
// Polymorphism here
objects.get(2)->method(asdf);
Hope this helps.
When you do this:
objects.add(obj);
you are adding a copy of the Object part of the MyObject to the list, so it is no longer a MyObject.
You might be tempted to try doing this:
int add(T const &p) {
if (length >= maxListLength) {
throw "Too many points!";
}
items[length] = p; // now the problem is here
return length++;
}
but now the copy of the Object part of p happens during the assignment.
To make the list be heterogeneous, it is going to have to be a list of pointers, but you also wanted to avoid dynamic memory allocation. You can avoid dynamic memory allocation if you are careful:
Object obj1;
MyObject obj2;
List<Object*> object_ptrs;
object_ptrs.add(&obj1);
object_ptrs.add(&obj2);
object_ptr.get(1)->method(input);
object_ptr.get(0)->method(input);
but again, you have to be very careful. The list is now pointing to the two objects on the stack. If you return from this function, those two objects will be destroyed. Note that I've purposefully put the list of object pointers after the objects, so that the list will get destroyed before the objects, so the list won't be left pointing to garbage. However, if you return a copy of the list, you would still have a problem.
Related
I want to allocate objects on the heap according to a string entered by the user but I cannot access the pointers or objects outside the function although they are on the heap. As well, I tried to allocate them using unique pointers but I'm still getting an error saying "not declared" etc.
How can I create these objects, a user can create eight objects concurrently with spaces between the words. (e.g. "Avalanche Toolbox Paperdoll" and so on)?
string user_input;
getline(cin, user_input);
istringstream iss(user_input);
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(vec));
for(int i=0; i<8; i++)
{
if(vec.at(i)=="Avalanche")
{
Avalanche *avalanche = new Avalanche(5);
std::unique_ptr<Avalanche> ptr(new Avalanche(5)); // even tried using unique pointer.
cout<<"Avalanche: "<<avalanche->c_game<<endl;
}
else if(vec.at(i)=="Bureaucrat")
{
Bureaucrat *bureaucrat = new Bureaucrat(5);
cout<<"Bureaucrat: "<<bureaucrat->c_game<<endl;
}
else if(vec.at(i)=="Toolbox")
{
Toolbox *toolbox = new Toolbox(5);
cout<<"Toolbox: "<<toolbox->c_game<<endl;
}
else if(vec.at(i)=="Crescendo")
{
Crescendo *crescendo = new Crescendo(5);
cout<<"Crescendo: "<<crescendo->c_game<<endl;
}
else if(vec.at(i)=="Paperdoll")
{
Paperdoll *paperdoll = new Paperdoll(5);
cout<<"Paperdoll: "<<paperdoll->c_game<<endl;
}
else if(vec.at(i)=="FistfullODollars")
{
Fistfullodollars *fistfullodollars = new Fistfullodollars(5);
cout<<"FistfullOdollars: "<<fistfullodollars->c_game<<endl;
}
}
cout<<ptr.c_game<<endl; // give an error not declared
Your object lifetime is limited to it's scope. In your case, the scope is within two closest {}. You need to remember that when you have a (smart)pointer to allocated memory, you actually have TWO objects - one is your (smart) pointer, and the other is the object the pointer points to. When the pointer goes out of scope, you can not reference the actual object by this pointer anymore. And if there is no other pointer pointing to this object, the object is lost forever, and you have is a classic example of so called memory leak - there is an object somewhere there, but is unaccessible, and the memory occupied by it is lost and can not be reused.
Think about it in a following way - you have a book and a library card. The book is somewhere in the vast storage, and unless you know where to look (using library card) you will never find it. So if you lost all copies of your library cards, the book is as good as lost to you - though it is obviously somewhere there.
The answer is, that your objects created are not deleted, since you have created them on the heap, as you pointed out, but the pointer variables go out of scope. The solution is, to put the declaration outside of the scopes and do the assignment in the scope:
string user_input;
getline(cin, user_input);
istringstream iss(user_input);
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(vec));
Bureaucrat *bureaucrat;
Toolbox *toolbox;
Crescendo *crescendo;
Paperdoll *paperdoll;
Fistfullodollars *fistfullodollars;
for(int i=0; i<8; i++)
{
if(vec.at(i)=="Avalanche")
{
Avalanche *avalanche = new Avalanche(5);
std::unique_ptr<Avalanche> ptr(new Avalanche(5)); // even tried using unique pointer.
cout<<"Avalanche: "<<avalanche->c_game<<endl;
}
else if(vec.at(i)=="Bureaucrat")
{
bureaucrat = new Bureaucrat(5);
cout<<"Bureaucrat: "<<bureaucrat->c_game<<endl;
}
else if(vec.at(i)=="Toolbox")
{
toolbox = new Toolbox(5);
cout<<"Toolbox: "<<toolbox->c_game<<endl;
}
else if(vec.at(i)=="Crescendo")
{
crescendo = new Crescendo(5);
cout<<"Crescendo: "<<crescendo->c_game<<endl;
}
else if(vec.at(i)=="Paperdoll")
{
paperdoll = new Paperdoll(5);
cout<<"Paperdoll: "<<paperdoll->c_game<<endl;
}
else if(vec.at(i)=="FistfullODollars")
{
fistfullodollars = new Fistfullodollars(5);
cout<<"FistfullOdollars: "<<fistfullodollars->c_game<<endl;
}
}
cout<<ptr.c_game<<endl; // give an error not declared
ptr is declared on the stack, it's the object it's pointing at which is delete bound.
when if(vec.at(i)=="Avalanche") {} is over, ptr (which is stack allocated) gets out of scope and no longer accesible.
Even if you allocate your object dynamically you still need a pointer variable to keep track of where that memory is. Your ptr variable is destroyed at the end of the enclosing braces.
I'm guessing all your classes Avalanche, Bureaucrat... inherit from some base class with a c_game member variable. Perhaps something a bit like this:
struct MyBase {
virtual ~MyBase(){} // This is important!
MyBase(std::string c_game) : c_game(c_game) {}
std::string c_game;
};
struct Avalanche : public MyBase {
Avalanche(int num) : MyBase("Avalanche"), num(num) {}
int num;
};
struct Fistfullodollars : public MyBase {
Fistfullodollars(int num) : MyBase("Fistfullodollars"), num(num) {}
int num;
};
//...
In order to keep track of these dynamically allocated objects you could construct a container of (smart) pointers to this base class:
std::vector<std::unique_ptr<MyBase>> objects;
for(size_t i=0; i!=vec.size(); i++)
{
if(vec.at(i)=="Avalanche")
{
objects.push_back(std::make_unique<Avalanche>(5));
std::cout<<"Avalanche: "<<objects.back()->c_game<<"\n";
}
else if(vec.at(i)=="FistfullODollars")
{
objects.push_back(std::make_unique<Fistfullodollars>(5));
std::cout<<"FistfullOdollars: "<<objects.back()->c_game<<"\n";
}
//...
}
for (const auto& ptr : objects)
{
std::cout << ptr->c_game << "\n";
}
Live demo.
I know that whenever I create a new object for a class, that object is stored in memory. I also know that in creating that object, it can only be accessed within the set of braces it is created in (Scope visibility). I need to find a way to delete that object outside of the braces it is created in. I have looked at smart pointers briefly, and it might be what I want to use? I'm assuming it is, I just don't know for sure. If a smart pointer can satisfy my needs, would someone please provide me with an example of how to use a smart pointer to access an object outside of where it has been created? Thanks :)
EDIT:
Example of what I'm trying to do:
class ModernWarfare2
{
//my class
ModernWarfare2();
};
DWORD XamHook(DWORD r3, DWORD r4, DWORD r5)
{
switch(XamGetCurrentTitleId())//a function that tells what game is being played
{
case Xbox360Dashboard://if i were to exit the game mw2
{
if(CODAllocated)//a boolean
{
//free the memory of the previous cod game
if(MW2Allocated)//another boolean
{
delete[] MW2;//gives me an error because i dont have access to MW2
}
}
break;
}
case COD_MW2:
{
if(!CODAllocated)
{
if(!MW2Allocated)
{
ModernWarfare2 *MW2 = new ModernWarfare2();
}
}
break;
}
}
return XamInputGetState(r3,r4,r5);
}
How do I fix my issue?
I also know that in creating that object, the object can only be accessed within the set of braces it is created in.
Not necessarily; that's only true when you construct objects with automatic storage duration, like this:
void foo()
{
T obj;
}
Such objects, yes, go out of scope.
Objects you allocate dynamically do not:
void foo()
{
T* obj = new T();
}
This is a memory leak because you never destroy *obj; however, you can access it from pretty much wherever you like:
T* foo()
{
return new T();
}
void bar()
{
T* obj = foo();
// yay!
}
or:
T* obj = nullptr;
void foo()
{
obj = new T();
}
void bar()
{
// do stuff with *obj
}
void baz()
{
foo();
bar();
}
This all gets dangerous and messy because you end up with spaghetti code in which the lifetime of the dynamically-allocated object is unclear, and in the examples above I still haven't approached the topic of eventually destroying the object. You have to be really careful not to destroy it whilst you're still using it.
This is where smart pointers come in, but if you want a tutorial on using smart pointers I'm going to have to refer you back to your C++11 book.
"I also know that in creating that object, the object can only be accessed within the set of braces it is created in." - This depends on how you create the object.
Example 1 (can't be accessed outside braces):
void func(void)
{
Object obj("foo", "bar");
}
Example 2 (can be accessed outside braces):
Object* func(void)
{
Object* obj = new Object("foo", "bar");
return obj;
}
Example 2 can be deleted using the keyword delete.
Take a look here for more information on pointers.
I haven't personally found a use for smart pointers but MSDN has good information on the topic here
By creating MW2 with
{
ModernWarfare2 *MW2 = new ModernWarfare2();
}
I was not able to reference MW2 elsewhere. By doing this, I can create it and delete it in two different spots:
class ModernWarfare2
{
//my class
ModernWarfare2();
};
ModernWarfare2 *MW2 = NULL;
DWORD XamHook(DWORD r3, DWORD r4, DWORD r5)
{
switch(XamGetCurrentTitleId())//a function that tells what game is being played
{
case Xbox360Dashboard://if i were to exit the game mw2
{
if(CODAllocated)//a boolean
{
//free the memory of the previous cod game
if(MW2Allocated)//another boolean
{
delete MW2;//gives me an error because i dont have access to MW2
}
}
break;
}
case COD_MW2:
{
if(!CODAllocated)
{
if(!MW2Allocated)
{
if(MW2 == NULL)
{
MW2 = new ModernWarfare2();
}
}
}
break;
}
}
return XamInputGetState(r3,r4,r5);
}
I think what you need is basic design pattern
Make the data and the functions members of a class
class SomeHandler
{
public:
void Acquire( /* some source */ );
void DoSomething( /* eventual parameters */ );
bool TrySomething(); // returns true if successful
private:
void internalFunction();
bool inGoodState;
SomeType dataINeed;
SomeOtherType otherData;
};
void SomeHandler::Acquire( /**/ )
{
// implement like this
}
now the functions can access the all the data
the use it like
int main()
{
SomeHandler h;
h.Acquire();
if( h.TrySomething() )
{
h.DoSomething();
}
}
Based on your code snippet, You have to save your pointer MW2 for
future so that you can delete the pointer.
I would suggest you to change
if(!MW2Allocated)
to
if(!MW2)
so that you don't have to create another variable for saving the reference to your allocated memory
Offcourse you have to move
ModernWarfare2 *MW2
to a larger scope (move it to the scope same as MW2Allocated) and initialize it to NULL.
Use "nullptr" instead of "NULL" if you are using C++11 supported compiler.
Also makesure you use
delete
instead of
delete[]
since this is not an array allocation
I don't think you can use smart pointers to skip saving your reference to the allocated memory,
since they are meant to make the memory deletion automatic or to make sure two deletion doesn't occur
for the same memory.
Refer to
http://www.codeproject.com/Articles/541067/Cplusplus-Smart-Pointers
for a good explanation about smart pointers
Code as follows:
#include "MyObject.h"
#include <vector>
#include <memory>
class MyCollection {
private:
std::vector<std::unique_ptr<MyObject*>> collection;
public:
MyCollection();
virtual ~MyCollection();
int insert(MyObject* newValue);
};
int MyCollection::insert(MyObject* newValue) {
if (collection.empty()) {
collection.push_back(move(make_unique<MyObject*>(newValue)));
return 0;
}
int index = collection.size()-1;
collection.resize(collection.size()+1);
vector<unique_ptr<MyObject*>>::reverse_iterator pos = collection.rbegin();
for ( ; (index >= 0) && (pos+1) != collection.rend() && stringToUpper((*(pos+1)->get())->getObjectName()) > stringToUpper(newValue->getObjectName()); ++pos) {
pos = (pos+1);
index--;
}
pos = ?newValue; // How do I do this?
//pos->reset(move(make_unique<MyObject*>(newValue)));
return index+1;
}
make_unique() implementation taken from http://scrupulousabstractions.tumblr.com/post/37576903218/cpp11style-no-new-delete
My question is there a way to do what I'm attempting with the assignment to the reverse_iterator (pos = newValue)? One of my pitiful attempts is shown in the commented code.
Thanks!
Firstly, as others have pointed out, you want a vector<unique_ptr<MyObject>> not vector<unique_ptr<MyObject*>>. It is fine to have a unique_ptr containing an abstract class (make sure the base class has a virtual destructor). You can implicitly cast from a unique_ptr containing a derived class.
Ideally I think MyCollection::insert should take a unique_ptr not a raw pointer so that the calling code creates objects using make_unique in the first place but let's leave it like it is for now.
I think you have a bit of confusion with make_unique. make_unique is designed to create an object and wrap it in a unique_ptr in one go, safely. Your MyCollection::insert doesn't really need to use make_unique because the object is already created. unique_ptr has a constructor that takes a raw pointer so you can create one directly from the raw pointer.
You can then push the unique_ptr onto the collection or replace unique_ptrs in the collection with new unique_ptrs fine:
class MyObject {
public:
virtual ~MyObject() = 0
};
MyObject::~MyObject() {}
class SimSolverObject : public MyObject {
};
class MyCollection {
private:
std::vector<std::unique_ptr<MyObject>> collection;
public:
void insert(MyObject* newValue);
};
void MyCollection::insert(MyObject* newValue) {
//...
// if we want to add to the collection
collection.push_back(std::unique_ptr<MyObject>(newValue));
// if we want to replace at iterator pos in collection
*pos = std::unique_ptr<MyObject>(newValue);
}
// calling code
MyCollection mc;
MyObject* newValue = new SimSolverObject();
mc.insert(newValue)
If you do decide to change MyCollection::insert to take a unique_ptr it would look something like this:
void MyCollection::insert(std::unique_ptr<MyObject> newValue) {
//...
// if we want to add to the collection
collection.push_back(std::move(newValue));
// if we want to replace at pos
*pos = std::move(newValue);
}
Edit: Your for loop looks a bit suspicious. I am not quite sure what you are trying to do but are you sure you want to increment the iterator twice? Once in the body of the for and once in the loop expression? I suspect the iterator is skipping over your condition and going out of bounds of the vector. When it hits the index condition you may be left with an invalid iterator.
vector<ClassX> xVec;
if (inputFile.peek() == '$')
{
classX classXInstance; //<==================== local instantiation
readFileElements(classXInstance);//<== pass by reference
if(classXInstance.validate())
{
xVec.push_back(classXInstance);///<=============== added here
}
/// destructor of the local copy is called here
}
I get a core dump, tried to debug, however I get so much junk messages with gdb, all I can see that the vector got corrupted, NOT sure if it because the destructor is called is a reason??
EDIT:
my class look like this
class ClassX
{
public:
ClassX() { numberOfX=0; ppXX = NULL; };
~ClassX();
void validate();
char **setX(const vector<string>& Xss);
inline char **getX() {return ppXX;};
private:
int numberOfX;
char **ppXX;
};
and it contains a destructor as follow
ClassX::~ClassX()
{
if (ppXX != NULL)
{
for(int i=0; i < numberOfXX; i++)
{
if (ppXX[i] != NULL)
{
delete [] ppXX[i];
ppXX[i] = NULL;
}
}
// Free array of pointers.
delete [] ppXX;
ppXX = NULL;
}
}
the setX allocate all memory necessary
validate give me a printout of the ppXX[i] and return true if number of elements matches the size of string vector
A copy of classXinstance is stored into xVec, with a pointer ppXX to a region in memory. Now you have two objects pointing to the same region. A moment later, classXinstance is destroyed, so the region is subject to delete. The element within xVec is now pointing to invalid memory.
The best option is to use std::Vector<std::string> instead of char **ppXX; a vector of strings takes care of references and allocation so you don't need to worry about proper construction/copy/destruction.
Title pretty much says it all, I'm almost positive it's either in the copy constructor or the assignment operator, and I'm pretty sure it's the latter. It's a pretty short class, so I'll post the entire thing, any advice on how to handle it would be good. I'm honestly a bit over my head here too, so any pointing to some solid reading would be greatly appreciated.
#pragma once
//for non-learning purposes, boost has a good smart pointer
template <class type>
class sPtr
{
private:
type *p;
int r; //referenceCount
void add()
{
r++;
}
int release()
{
return --r;
}
public:
sPtr(): p(NULL), r(1) {}
sPtr(type *pValue): p(pValue)
{
add();
}
sPtr(const sPtr<type> & sp): p(sp.p), r(sp.r)
{
add();
}
~sPtr()
{
if(release() == 0)
{
delete p;
}
}
type* get()
{
return p;
}
type& operator*()
{
return *p;
}
type* operator->()
{
return p;
}
sPtr<type>& operator=(sPtr<type> sp)
{
std::swap(this->p, sp.p);
std::swap(this->r, sp.r);
add();
return *this;
}
};
I'm pretty sure that the assignment operator should be passed by reference, but I'm not sure on how this will affect the implementation. I tried a few different implementations and all of them still had the leak.
Each of your shared pointers keeps track of its own separate reference count. This is obviously no good. When one is destroyed, the ref count on the others is not updated. You need to keep the reference count in a separate location that all the shared pointers have access to.
In addition to what Ben already mentioned, you are starting your reference count at 1 in your default constructor (and not initializing it at all in your others). If you assign a pointer to it after the default constructor, your reference count would be 2, and when you call release, back to 1. In short, the only time your reference count would be 0 (indicating you can delete the object) is if you call release 1 more time than add was called. Typically, you want those calls to be symmetrical (call to add corresponds to call to release).