vector of class scope issue? - c++

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.

Related

Deleting dynamic elements in a vector

I have a program that has a vector. The vector takes pointers to an object which I dynamically create in my program. I then wish to delete these dynamic objects from the vector. For example:
int main()
{
vector<Account*> allAccounts;
auto timeDone = chrono::system_clock::now();
time_t transactionTime = chrono::system_clock::to_time_t(timeDone);
Account* a1 = new Savings(0, "Savings");
Account* a2 = new Current(0, "Current");
allAccounts.push_back(a1);
allAccounts.push_back(a2);
Transaction* initialTransaction = new Transaction("Initial Deposit", transactionTime, balanceAnswer);
allAccounts[0]->addTransaction(initialTransaction);
allAccounts[1]->addTransaction(initialTransaction);
for (int i = 0; i < allAccounts.size(); i++)
{
delete allAccounts[i]; //deletes all dynamically created accounts
}
}
I believed this was fine to do, however I'm starting to wonder if this does correctly delete the pointers in the vector. However I used a cout << allAccounts.size() after the delete and it still gives the size as 2 as if the account pointers were still in the vector.
Is this meant to happen?
Another note is that the Account object also has a vector of dynamic pointers that get passed from main in a function (allAccounts[i]->addObject(object)) and then these objects get deleted in a destructor in the same way. Is this also a valid thing to do?
Just so I get my worries out the way, this is what I do in account:
float balance;
string accountType
private vector <Transaction*> history;
Account::Account(float b, string a)
{
balance = b;
accountType = a;
}
void Account::addTransaction(Transaction* t)
{
history.push_back(t);
}
Account::~Account()
{
for (int i = 0; i < history.size(); i++)
{
delete history[i];
}
history.clear();
}
What you are doing is fine (assuming Account has a virtual destructor) and there is no memory leak. The size of the vector is not affected by deleting the pointers you store in it.
The destructor needs to be virtual to not cause your program to have undefined behavior.
I would recommend storing a smart pointer like std::unique_ptr<Account> in the vector instead though. That would make the destruction of the stored objects automatic when the vector.is destroyed.

2d array memory management issue

I have to write a code that gets a string and turns it into an object of a class. Everything is working as expected but I'm unable to deallocate the dynamically allocated 2d array of objects.
I know the issue is within the destructor and the Move assignment operator for the object, I keep getting SIGBRT and EXC_BAD_ACCESS errors when I try to run it.
Below is my Code for the constructor, destructor and move assignment/constructor
//CustomerOrder.cpp
CustomerOrder::CustomerOrder(std::string&
src):Name(src),Product(),ItemCount(),ItemList(),field_width(){
std::vector<ItemInfo> info;
std::string* tokens[] = { &Name, &Product };
Utilities utils;
size_t next_pos = -1;
bool more = true;
for (auto& i : tokens) {
if (!more) break;
*i = utils.extractToken(src, next_pos, more);
}
while (more){
info.push_back(utils.extractToken(src, next_pos, more));
}
if(!info.empty() && info.back().ItemName.empty()){
info.pop_back();
}
ItemCount = info.size();
ItemList = new ItemInfo*[ItemCount];
for (int i = 0; i < ItemCount; i++){
ItemList[i] = new ItemInfo(info.at(i).ItemName);
}
if (utils.getFieldWidth() > field_width){
field_width = utils.getFieldWidth();
}
}
CustomerOrder::~CustomerOrder(){
for(int i = 0; i<ItemCount;i++){
delete[] ItemList[i];
}
delete[] ItemList;
}
CustomerOrder::CustomerOrder(CustomerOrder&& src){
*this = std::move(src);
}
CustomerOrder& CustomerOrder::operator=(CustomerOrder&& src){
if(this!= &src){
delete [] ItemList;
Name = std::move(src.Name);
Product = std::move(src.Product);
ItemCount = std::move(src.ItemCount);
ItemList = std::move(src.ItemList);
src.ItemList = nullptr;
}
return *this;
}
And the ItemInfo struct
//ItemInfo struct
struct ItemInfo
{
std::string ItemName;
unsigned int SerialNumber;
bool FillState;
ItemInfo(std::string src) : ItemName(src), SerialNumber(0),
FillState(false) {};
};
You are combining "new" with "delete[]". If you use "new" use "delete" if you use "new[]" then use "delete[]" for the thing.
This is your problem there: "delete[] ItemList[i];" it should be "delete ItemList[i];" instead
This line of your code ItemList[i] = new ItemInfo(info.at(i).ItemName); doesn't allocate a dynamic array, yet this code in your destructor tries to delete it as thought it was a dynamic array.
for(int i = 0; i<ItemCount;i++){
delete[] ItemList[i];
}
A quick fix would to be to change delete[] to delete. However, it appears as though it would be much easier to simply allocate a single dynamic array. In other words, allocate ItemList as such ItemList = new ItemInfo[ItemCount]; Granted, you would have to change the type, but it makes more sense from what you posted.
Another possible issue is that in your destructor you don't check if the ItemList is a nullptr or actually allocated to anything. To which, your destructor could possibly try to access invalid data. Not only that, but your move operator deletes the ItemList without deleting the data inside of it.
You could make a function to free up the data in ItemList and then call that function from the destructor and move operator.
On a side note, why are you using dynamic 2D arrays when it appears that you know how to use vectors? A vector would handle all of this in a much simpler fashion. For example, the type would be std::vector<std::vector<ItemInfo>>.

why is the dynamically allocated object going out of scope outside the function?

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.

How to call virtual function of an object in C++ [duplicate]

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.

Swapping an object within itself

I'm trying to swap an object within itself. It works but when I add a destructor it gives me a double free error. Is there a way to prevent this? The method I'm talking about is void swap(SimpleArray &object).
(Sorry if you read this before I had the wrong info in my post...)
#include "TestType.h"
class SimpleArray {
private:
TestType* pArray;
//TestType* temp;
public:
SimpleArray(TestType *array)
{
this->pArray = array;
}
~SimpleArray() { delete[] pArray; }
SimpleArray() { pArray = 0;}
SimpleArray(const SimpleArray& arg){ pArray = arg.pArray; }
~SimpleArray() { delete[] pArray; }
TestType * get() const{ return pArray; }
bool isNonNull() const { return pArray != 0; }
//TestType* pArray;
void reset(TestType*& p) {this->pArray = p; }
void reset() { pArray = 0; }
void swap(SimpleArray &object) { SimpleArray temp; temp = object; object = *this; *this = temp;}
TestType * release() { pArray = 0; return pArray; }
TestType& getReference(int a) { return *pArray; }
};
This works but once I add the destructor it gives me a "double free or corruption error". How do I solve this? Here's the function in main where it messes up.
bool testGetReleaseSwap() {
SimpleArray array1;
if (array1.get() != 0)
return false;
TestType* directArray1 = new TestType[100];
array1.reset(directArray1);
if (array1.get() != directArray1)
return false;
TestType* directArray2 = new TestType[50];
SimpleArray array2(directArray2);
array1.swap(array2);
if (array1.get() != directArray2 || array2.get() != directArray1)
return false;
array2.swap(array1);
if (array1.get() != directArray1 || array2.get() != directArray2)
return false;
array1.swap(array1);
if (array1.get() != directArray1)
return false;
if (array1.release() != directArray1 || array2.release() != directArray2)
return false;
if (array1.get() != 0 || array2.get() != 0)
return false;
delete[] directArray1;
delete[] directArray2;
return true;
}
The trivial way out here is to invoke temp.release() at the end if your swap method to prevent double deletion.
The underlying issue is much deeper, though. In C++ it is crucial to always maintain strict semantics of who owns something, for example a memory region that requires deletion.
A frequent pattern is that the object that allocates something is also responsible for cleaning up and no one else. This fits nicely with SimpleArray, but the copy constructor breaks it because it multiplies the number of owners!
To implement shared data semantics you have to invest more work (reference counting etc.) or you have to forbid array copying and make the copy constructor private.
A clean way to fix up swap to work without copying the object would be:
void swap(SimpleArray &object) {
TestType* temp = object.pArray;
object.pArray = this->pArray;
this->pArray = temp;
}
(std::swap(object.pArray, pArray); works as well)
Because to swap the memory regions of the array fits nicely with a single-owner pattern, what went wrong here is only the use of the full object copy.
You should read up on resource management and ownership semantics in C++. Your code will always be error prone unless you absolutely know who owns what.
It seems to me that you are trying to implement a class that has shallow copy semantics (and possibly copy-on-write). To do that successfully you need to track how many other owners of the shared data are still around and need to destroy the owned object, when that count reaches zero. You can either use a std::shared_ptr for that or implement the reference counting yourself.
As for the real problem in that specific example, look at what you copy constructor is doing. It is not copying but simply taking another reference (a pointer to be specific) to the object that is already owned by its argument. That by itself already enough to get a double free and your swap testcase is simply exposing that issue.