For future visitors
It turns out I didn't have a copy assignment operator defined in my custom class, and therefore the compiler defaulted to "copy the object's pointer" behavior.
If you're confused about what a copy assignment operator is, just like I was, this resource may help you figure out what a "copy assignment operator" looks like in C++.
The original problem prompt is below. (Links to the original source code will expire in a month; sorry!)
I'm working on a console application which simulates a bookstore, but keep on getting a _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) error message in my program during execution. After doing some searching around (and some frustrating debugging), I've come to the conclusion that my object's destructor is getting called twice. I hope the code snippets below will make it a little clearer what I mean. (Clicking on the file names will open a pastie with the relevant code for easier reading/decluttering.)
bookdata.h
#ifndef BOOKDATA_H
#define BOOKDATA_H
class bookData {
private:
char* bookTitle;
char* isbn;
char* author;
char* publisher;
char* dateAdded;
int qtyOnHand;
double wholesale;
double retail;
public:
bookData();
bookData(char* title, char* isbn, char* author, char* publisher, char* date, int qty, double wholesale, double retail);
bookData(bookData& book); // Meant to be called during memberwise assignment
~bookData();
// Various setter & getter funcs
};
#endif
bookData.cpp
#include "globals.h"
#include "bookData.h"
using namespace std;
// Variables in caps are const ints defined in globals.h
bookData::bookData() {
bookTitle = new char[TITLE_LENGTH];
isbn = new char[ISBN_LENGTH];
author = new char[AUTHOR_LENGTH];
publisher = new char[PUBLISHER_LENGTH];
dateAdded = new char[DATE_LENGTH];
qtyOnHand = 0;
wholesale = 0;
retail = 0;
char emptyTitle[2];
emptyTitle[0] = '\0';
setTitle(emptyTitle);
}
// Other constructors are overloaded version of bookData & copy data;
// See example setter function below destructor
bookData::~bookData() {
if (bookTitle)
delete [] bookTitle;
else
return;
delete [] isbn;
delete [] author;
delete [] publisher;
delete [] dateAdded;
}
// Setter functions are of this form (excl. ints & doubles)
void bookData::setTitle(const char* input) {
for (int len = 0; len < TITLE_LENGTH - 1; len++) {
*(bookTitle + len) = *(input + len);
if (*(input + len) == '\0')
break;
else if (len == TITLE_LENGTH - 2)
*(bookTitle + ++len) = '\0';
}
}
// Getter functions are of this form (excl. ints & doubles)
const char* bookData::getTitle() { return bookTitle; }
reports.cpp (the file that's calling the destructor twice)
void repQty() {
// Again, variables in all caps are defined in globals.h if you don't see
// their declaration
bookData bookArray[MAX_RECORDS];
// Global function which populates bookArray from a datafile
bookData* books = getBooks(bookArray);
// Some code to find the memory address of the first and last book in the records
bookData* HEAD = books;
// Keep advancing until books no longer points to a non-empty bookData object
// "Empty" defined as book's bookTitle variable starting with '\0'
bookData* TAIL = --books;
// Need all 3 pointers for a naive, in place insertion/linear sort routine
// Outputs book data following the sort
// Before returning, calls the destructors for the books in bookArray
// Also calls the destructor for books, HEAD, and TAIL as well
// ...which were already called as part of the bookArray's destructor calls
// Which is where I have my problem now
}
Bonus: globals.h
As you may have noticed, I've already attempted to check whether the bookData object has already been deleted by using if (bookTitle) in the destructor function, but it still evaluates as true when I'm running it through VS's Step Into functionality. Short of nuking the destructor all together, what can I do to get around this problem and make the destructor prematurely exit if the object in question has already been deallocated?
I've already attempted to check whether the bookData object has already been deleted by using if (bookTitle) in the destructor function
Since delete[] doesn't set the pointer to NULL, the check is effectively a no-op.
Even if you set the pointer to NULL manually, you'd be tackling the symptoms of the problem rather than the root cause.
The root cause is that you're not implementing the copy assignment operator, thereby violating the rule of three. What happens is that you're using the implicitly-generated copy assignment operator:
swap = *books;
*books = *(books - 1);
*(books - 1) = swap;
and that operator doesn't do the right thing: it copies the pointers instead of copying the data. The double deletes are a direct consequence of that.
Additionally, the implementation of the copy constructor could be buggy, but it's hard to be sure without seeing its source code.
P.S. You'd do yourself a massive favour by using std::string instead of C strings. Also, std::vector is to be preferred to C arrays.
Related
I tried to search same questions, but not one helped me. When I run program I get the "A Buffer Overrun has occurred..." error.
Constr:
Player(char* n)
{
length = strlen(n);
name = new char[length+1];
for(unsigned int i(0); i < length; i++)
name[i] = n[i];
name[length] = '\0';
}
Destr:
~Player(void)
{
delete [] name;
}
I've NULL terminated string and don't get out of bounds, what is problem?
There's no obvious error in the code you've posted, but trying to manage dynamic memory by juggling raw pointers will almost inevitably lead to errors like this.
Perhaps you haven't correctly implemented or deleted the copy constructor and copy-assignment operator, per the Rule of Three. In that case, copying a Player object will give two objects with pointers to the same array; both of them will try to delete that array, giving undefined behaviour.
The simplest solution is to manage your string with a class designed for managing strings. Change the type of name to std::string, and then the constructor can simply be something like
explicit Player(std::string const & n) : name(n) {}
and there's no need to declare a destructor (or move/copy constructor/assignment operators) at all.
So... a solution by using an std::string has been provided, but let me give another solution, keeping your member variables intact.
The problem is this. Suppose you have this code somewhere:
Player p1("Bob"); // Okay
Player p2("Annie"); // Okay
p2 = p1; // Oops! (1)
Player p3(p1); // Oops! (2)
At (1), the method Player& Player::operator=(const Player&) is called. Since you didn't provide one, the compiler generates one for you. When it does, it simply assumes that it may copy over all member variables. In this case, it copies over Player::name and Player::length. So, we have p1.name == p2.name. Now when the destructor of p2 is called, the allocated memory pointed to by p2.name is deleted. Then when the destructor of p1 is called, the same memory will be deleted (since p1.name == p2.name)! That's illegal.
To fix this, you can write an assignment operator yourself.
Player& Player::operator = (const Player& other)
{
// Are we the same object?
if (this == &other) return *this;
// Delete the memory. So call the destructor.
this->~Player();
// Make room for the new name.
length = other.length;
name = new char[length + 1];
// Copy it over.
for (unsigned int i = 0; i < length; ++i) name[i] = other.name[i];
name[length] = '\0';
// All done!
return *this;
}
At (2), the same problem occurs. You do not have a copy constructor, so the compiler generates one for you. It will also assume that it may copy over all the member variables, so when the destructors get called, they'll try to delete the same memory again. To fix this, also write a copy constructor:
Player::Player(const Player& other)
{
if (this == &other) return;
length = other.length;
name = new char[length + 1];
for (unsigned int i = 0; i < length; ++i) name[i] = other.name[i];
}
At the end of the day you should use an std::string though.
I am not going to past the whole source because it is 1000+ rows, but I have specially constructed a similar case about the matter I am interested in. Pay attention to this source code:
#include <iostream>
using namespace std;
class Person
{
public:
Person();
Person(char*);
~Person();
Person& operator=(const Person&);
friend Person& example(const Person&);
void print() const;
private:
char* name;
};
Person::Person()
{
name = new char[12];
name = "Temp";
}
Person::~Person()
{
delete[] name;
}
Person::Person(char* _name)
{
name = new char[strlen(_name)+1];
strcpy_s(name,strlen(_name)+1,_name);
}
Person& example()
{
char* TestName = new char[11];
TestName = "ShouldStay";
Person B(TestName);
return B;
}
void Person::print() const
{
cout << name;
}
int main()
{
example();
return 0;
}
In this case the example() function will return:
example returned {name=0x007cad88 "îþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþ... } Person &
So obviously the destructor is called on the return command and delete the memory in the heap (so I am not able to do anything further with the pointer - it is pointing to already freed memory - no data).
My question is - How to avoid such behavior? What is the most elegant way to avoid such issue?
Thank you in advance!
Use string rather than char[] to avoid having to use new.
Return Person rather than Person&, as locally-scoped classes
are destroyed after they leave scope. Although this will cause a
copy to happen depending on compiler settings. This depends of course upon providing a proper copy constructor.
To guarantee avoiding a copy, change the signature of example to:
void example(Person& person)
And fill in the fields of the inputted person inside the function. The scope of that Person will be bound to the calling scope (or wherever else you constructed it). This method has drawbacks though such as you cannot chain the results together.
Your code contains many logical errors:
Person::Person()
{
name = new char[12];
name = "Temp";
}
In the above function you allocate a char array of 12 elements, then you simply forget about it and instead make name pointing to a string literal.
Person::~Person()
{
delete[] name;
}
whoopps. In case Person was build from a default constructor this would delete a string literal. A no-no in C++.
Person::Person(char* _name)
{
name = new char[strlen(_name)+1];
strcpy_s(name,strlen(_name)+1,_name);
}
Not 100% sure what strcpy_s is, but the code in this case allocates an array and seems to copy the string into the array. This seems ok (but just strcpy(name, _name); would have been better for many reasons).
Person& example()
{
char* TestName = new char[11];
TestName = "ShouldStay";
Person B(TestName);
return B;
}
This code is seriously broken. First of all it's returning by reference a temporary object. A Very Very Bad Idea. It's also allocating an array, and once again just forgetting about it and using a string literal instead.
The most elegant way (actually the ONLY way in my opinion) to get your code working is to first understand how the basics of C++ work. You should start first by reading a good C++ book from cover to cover, and only then you should start coding in C++.
Your 1000 lines of source code are most probably just rubbish. I'm not saying you're dumb, just that you don't know the basics of C++. Take care of them first by reading, not experimenting with a compiler.
You cannot learn C++ by experimenting for two reasons:
It's a complicate and sometimes even just downright illogical language because of its history. Guessing is almost always a bad move. No matter how smart you are there's no way you can guess correctly what a committee decided.
When you make a mistake there are no runtime error angels to tell you so. Quite often it happens that apparently the program works anyway... until it's run by your teacher, boss or spouse. Guessing C++ rules by writing code and observing what happens is nonsense.
Person& example()
{
char* TestName = new char[11];
TestName = "ShouldStay";
Person B(TestName);
return B;
}
The above creates an instance of Person on the stack, scoped to the function. So when the function returns, the destructor for Person is called and a reference to the destroyed object (on the stack) is returned.
In addition you should either consider returning a copy of Person, or you need to use the new operator to create an instance of person on the heap and return a pointer to that.
At my university, there is a practical programming test in C++ - and I'm stuck with an example where I am unsure about wheter or not the task in question is even valid and possible to complete correctly.
The (simple) tasks:
Complete the destructor of Person, so that the allocated name is freed again
In the main function, replace //??? with the statement required to free the previously allocated memory
At first, the tasks seemed trivial for me: For the destructor, simply write delete[] name and in the main function, use delete[] friends. Presumably, that is also what the author of this example meant us to do.
However:
There seems to be a flaw in this code example, which causes memory leaks as well as destructors to be called more than once.
The person class has no assignment operator =, meaning that as the existing Person objects such as maria are assigned to slots in the friends array in the main function, the internal allocated names are not copied. So two objects now share the same internal char* pointer! Moreover, the pointer to the name of the Person previously residing in the said array slot is permanentely lost, leading to an unavoidable memory leak.
As delete[] friends; is called - the objects in the array are destroyed - leading to their destructors being called and freeing their name members. When the program ends, though, the local Person objects in the scope of main are destructed - which of course have their name members still pointing to memory which was already freed before.
The actual question:
Is this test example flawed, or am I missing something?
Can the issues listed above be fixed if sticking fully to carrying out the given tasks (altering just the implementation of the destructor, and inserting new code at the commented part in the main function)?
..
#include <iostream>
using namespace std;
int strlen(const char *str) {
if (str==0) return 0;
int i=0;
for (; str[i]; ++i);
return i;
}
void strcpy(const char *src, char *dest) {
if (src==0 || dest==0) return;
int i=0;
for (; src[i]; ++i) dest[i]=src[i];
dest[i]=’\0’;
}
class Person {
char *name;
public:
Person(const char *str = "Susi") {
name = new char[strlen(str)+1];
strcpy(str,name);
}
Person(const Person &p) {
name = new char[strlen(p.name)+1];
strcpy(p.name,name);
}
~Person() {
//...
}
void change() {
name[4]='e';
}
ostream &print(ostream &o) const {
o<<name;
return o;
}
};
int main() {
Person maria("Maria"), peter("Peter"), franz("Franz"), luisa("Luisa");
Person mary(maria);
Person luise;
Person p(luise);
Person *friends= new Person[7];
friends[0]=maria;
friends[1]=peter;
friends[2]=franz;
friends[3]=luisa;
friends[4]=mary;
friends[5]=luise;
friends[6]=p;
friends[5]=luisa;
friends[3].change();
friends[4].change();
for (int i=0; i<7; ++i) {
friends[i].print(cout);
cout<<endl;
}
//???
return 0;
}
You are absolutely right. You can fix it by only making changes at the indicated positions, however they are going to be rather extreme:
Replace the //... inside the destructor with:
delete[] name;
}
Person& operator=(const Person& other)
{
if (this != &other) {
delete[] name; // not completely exception-safe!
name = new char[strlen(other.name)+1];
strcpy(other.name,name);
}
return *this;
Another serious problem is redefining a standard function (strcpy) with a new definition that reorders the arguments.
(See also: SQL injection attacks, which also cause existing pairs of syntax elements, frequently quotes and parentheses, to be re-paired with inserted syntax elements)
Yes, the test example is flawed, possibly it was done consciously. Class Person definitely need assignment operator, remember the Rule Of Three.
No, it's not possible. Default compiler-generated assignment operator will leak memory allocated by objects in friends array and double-delete memory allocated by auto Person objects.
For every new there should be a delete[].
Have a homework assignment in which I'm supposed to create a vector of pointers to objects
Later on down the load, I'll be using inheritance/polymorphism to extend the class to include fees for two-day delivery, next day air, etc. However, that is not my concern right now. The final goal of the current program is to just print out every object's content in the vector (name & address) and find it's shipping cost (weight*cost).
My Trouble is not with the logic, I'm just confused on few points related to objects/pointers/vectors in general. But first my code. I basically cut out everything that does not mater right now, int main, will have user input, but right now I hard-coded two examples.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Package {
public:
Package(); //default constructor
Package(string d_name, string d_add, string d_zip, string d_city, string d_state, double c, double w);
double calculateCost(double, double);
~Package();
private:
string dest_name;
string dest_address;
string dest_zip;
string dest_city;
string dest_state;
double weight;
double cost;
};
Package::Package()
{
cout<<"Constucting Package Object with default values: "<<endl;
string dest_name="";
string dest_address="";
string dest_zip="";
string dest_city="";
string dest_state="";
double weight=0;
double cost=0;
}
Package::Package(string d_name, string d_add, string d_zip, string d_city, string d_state, string r_name, string r_add, string r_zip, string r_city, string r_state, double w, double c){
cout<<"Constucting Package Object with user defined values: "<<endl;
string dest_name=d_name;
string dest_address=d_add;
string dest_zip=d_zip;
string dest_city=d_city;
string dest_state=d_state;
double weight=w;
double cost=c;
}
Package::~Package()
{
cout<<"Deconstructing Package Object!"<<endl;
delete Package;
}
double Package::calculateCost(double x, double y){
return x+y;
}
int main(){
double cost=0;
vector<Package*> shipment;
cout<<"Enter Shipping Cost: "<<endl;
cin>>cost;
shipment.push_back(new Package("tom r","123 thunder road", "90210", "Red Bank", "NJ", cost, 10.5));
shipment.push_back(new Package ("Harry Potter","10 Madison Avenue", "55555", "New York", "NY", cost, 32.3));
return 0;
}
So my questions are:
I'm told I have to use a vector
of Object Pointers, not Objects.
Why? My assignment calls for it
specifically, but I'm also told it
won't work otherwise.
Where should I be creating this
vector?
Should it be part of my Package
Class? How do I go about adding
objects into it then?
Do I need a copy constructor? Why?
What's the proper way to deconstruct
my vector of object pointers?
Any help would be appreciated. I've searched for a lot of related articles on here and I realize that my program will have memory leaks. Using one of the specialized ptrs from boost:: will not be available for me to use. Right now, I'm more concerned with getting the foundation of my program built. That way I can actually get down to the functionality I need to create.
Thanks.
A vector of pointers can be reused for storing objects of sub-classes:
class Person
{
public:
virtual const std::string& to_string () = 0;
virtual ~Person () { }
};
class Student : public Person
{
const std::string& to_string ()
{
// return name + grade
}
};
class Employee : public Person
{
const std::string& to_string ()
{
// return name + salary
}
};
std::vector<Person*> persons;
person.push_back (new Student (name, grade));
person.push_back (new Employee (name, salary));
person[0]->to_string (); // name + grade
person[1]->to_string (); // name + salary
Ideally the vector should be wrapped up in a class. This makes memory management easier. It also facilitates changing the support data structure (here an std::vector) without breaking existing client code:
class PersonList
{
public:
Person* AddStudent (const std::string& name, int grade)
{
Person* p = new Student (name, grade);
persons.push_back (p);
return p;
}
Person* AddEmployee (const std::string& name, double salary)
{
Person* p = new Employee (name, salary);
persons.push_back (p);
return p;
}
~PersonList ()
{
size_t sz = persons.size ();
for (size_t i = 0; i < sz; ++i)
delete persons[i];
}
private
std::vector<Person*> persons;
};
So we can re-write our code as:
{
PersonList persons;
Person* student = persons.AddStudent (name, grade);
Person* employee = persons.AddEmployee (name, salary);
student.to_string ();
employee.to_string ();
} // The memory allocated for the Person objects will be deleted when
// `persons` go out of scope here.
Getting familiar with the Rule of Three will help you decide when to add a copy constructor to a class. Also read about const correctness.
Question 1:
You mentioned inheritance. Since inherited objects often need more bytes of storage, they don't fit into the place of a base object. If you try to put them in, you get a base object instead. This is called object slicing.
Question 2:
Design first, before you write code. There are a bunch of possible solutions.
For a start you can keep it in main(), but later you will be forced to make a class like PackageContainer for holding your objects.
Question 3 + 4:
You need a copy constructor, an assignment operator= and a destructor, when a class object owns dynamically allocated objects (the Rule of the Big Three). So a PackageContainer will probably need them.
You create objects dynamically using new Object(..). You are responsible for destroying them and for giving their memory back to the system immediately before your vector of pointers is destroyed:
for (size_t i = 0; i < shipment.size(); ++i)
{
delete shipment[i];
}
Since working with naked pointers to dynamically allocated objects is not safe, consider using
std::vector<tr1::shared_ptr<Package> > shipment;
instead or
std::vector<std::shared_ptr<Package> > shipment;
if your compiler understands C++0x. The shared_ptr handles freeing memory for you: It implements the Rule of the Big Three for one object pointer. It should be used in production quality code.
But try to get it right with naked pointers also. I think that's what your homework assignment is about.
I'm told I have to use a vector of Object Pointers, not Objects. Why? My assignment calls for it specifically, but I'm also told it won't work otherwise.
Usually, one would avoid using vector of objects to avoid the problem of Object Slicing. To make polymorphism work You have to use some kind of pointers. I am not sure of how the classes in your assignment are aligned but probably you might have Inheritance there somewhere and hence if vector is storing objects of Base class and you insert objects of Derived class in it then it would cause the derived class members to slice off.
The Best solution will be to use a smart pointer instead of a Raw pointer. The STL has an auto_ptr, but that cannot be used in a standard container.Boost smart pointers would be a best solution but as you already said you can't use Boost So in your case you can use your compiler's implementation of smart pointers, which comes in TR1 namespace,remember though that there is some disagreement on the namespace for TR1 functions (Visual C++ puts them in std::, while GCC puts them in std::tr1::).
Where should I be creating this vector? Should it be part of my Package Class? How do I go about adding objects into it then?
Your example code already has an example of adding a pointer to Package class in a vector. In a nutshell you will dynamically allocate pointers to Package and then add them to the vector.
Do I need a copy constructor? Why?
The copy constructor generated by the compiler does member-wise copying. Sometimes that is not sufficient. For example:
class MyClass {
public:
MyClass( const char* str );
~MyClass();
private:
char* str;
};
MyClass::MyClass( const char* str2 )
{
str = new char[srtlen( str2 ) + 1 ];
strcpy( str, str2 );
}
Class::~Class()
{
delete[] str;
}
In this case member-wise copying of str member will not duplicate the buffer (only the pointer will be copied(shallow copy)), so the first to be destroyed copy sharing the buffer will call delete[] successfully and the second will run into Undefined Behavior. You need deep copying copy constructor (and assignment operator as well) in such a scenario.
When to use a custom copy constructor is best defined by the Rule Of Three:
Whenever you are writing either one of Destructor, Copy Constructor or Copy Assignment Operator, you probably need to write the other two.
What's the proper way to deconstruct my vector of object pointers?
You will have to explicitly call delete on each contained pointer to delete the content it is pointing to.
vector::erase
Removes from the vector container and calls its destructor but If the contained object is a pointer it doesnt take ownership of destroying it.
Check out this answer here to know how to corrctly delete a vector of pointer to objects.
I am attempting to dynamically allocate memory to the heap and then delete the allocated memory. Below is the code that is giving me a hard time:
// String.cpp
#include "String.h"
String::String() {}
String::String(char* source)
{
this->Size = this->GetSize(source);
this->CharArray = new char[this->Size + 1];
int i = 0;
for (; i < this->Size; i++) this->CharArray[i] = source[i];
this->CharArray[i] = '\0';
}
int String::GetSize(const char * source)
{
int i = 0;
for (; source[i] != '\0'; i++);
return i;
}
String::~String()
{
delete[] this->CharArray;
}
Here is the error I get when the compiler tries to delete the CharArray:
0xC0000005: Access violation reading location 0xccccccc0.
And here is the last call on the stack:
msvcr100d.dll!operator delete(void * pUserData) Line 52 + 0x3 bytes C++
I am fairly certain the error exists within this piece of code but will provide you with any other information needed. Oh yeah, using VS 2010 for XP.
Edit: Heres my String.h
// String.h - string class
#pragma once
#define NOT_FOUND -1
class String
{
public:
String();
String(char* source);
static int GetSize(const char * source);
int Find(const char* aChar, int startPosition = 0);
~String();
private:
char* CharArray;
int Size;
};
Change your default ctor; given the error you're getting, the delete call is trying to delete a pointer that has never been initialized.
String::String() : Size(0), CharArray(NULL) {}
Also, beware of the "copy constructor". You might want to make it private just to be sure you're not triggering it implicitly. (It doesn't need to be implemented if you don't intend to call it, just stick the function prototype into your class definition.) Might as well similarly "disable" the assignment operator.
class String
{
// other stuff
private:
String(String&);
String& operator=(String&);
};
This addition fulfills the "Rule of Three," which says that if any class needs a destructor, a copy constructor, or an assignment operator, it probably needs all three.
Edit: see http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
String::String(): CharArray( 0 ) {}
You're not initializing CharArray in every constructor, so in some cases you're deleting an uninitialized pointer.
You have multiple constructors, but only 1 of them calls new. Your destructor always calls delete so there is your error.
I think #dash-tom-bang is correct. You're probably copying String and then deleting its data twice. I'll keep my old answers here for reference, though.
You're going to need to post the code that uses String, but I can notice a few problems here:
What if source is NULL in the constructor? Immediately you have a Null Pointer Exception. What's worse, if you get this exception, the destructor will attempt to delete memory that was never allocated. This could cause the error described above if you're using try...catch.
GetSize should not be a member function of String because it doesn't use any member variables. At the very least it should be static.