First of all, I was not using C++ for a lot time and it is possible that this question is very easy and it does not deserve to be posted here. Anyway, I did not found any solution here or in other source.
My problem consists in following. Let's assume we have class A:
Class A
{
char* string;
public:
char*& getString(){ return string; }
~A()
{
if (string)
delete[] string;
}
};
I cannot modify this class(it is just a sample of the real class).
I want to set field string to a value:
int main()
{
A a;
a.getString() = new char[3];
a.getString() = "Hi\0";
return 0;
}
This code cause Debug Assertion Fail when destructor ~A() is called. What I'm doing wrong here?
I really will appreciate any suggestion about what I'm doing wrong.
EDIT:
It seems, that assignment operator here is important. Actually, I'm doing such an assignment:
int main()
{
A a;
char name[256];
std::cin.getline(name, 256);
a.getString() = new char[strlen(name)];
//actual version
strcpy_s(a.getString(), strlen(name), name);
//a.getString() = "Hi\0";
return 0;
}
This code cause Debug Assertion Fail when destructor ~A() is called. What I'm doing wrong here?
a.getString() = "Hi\0";
After this line, a.string points to a string literal. The destructor will then call delete[] on the pointer. Deleting a string literal has undefined behaviour. Also, the previously allocated dynamic array is leaked, since the pointer was overwritten.
The solution is to remove the quoted line.
Related
I Have a doubt in the following code, there is a destructor delete line[] inside the destructor, I just want to know if there any stack over flow for this delete which can be a result of recursive call to destructor.
class Line {
public:
char *line;
Line(const char *s = 0) {
if (s) {
line = new char[strlen(s)+1];
strcpy(line, s);
} else {
line = 0;
}
}
~Line() {
delete[] line; //----------> how this delete will work?
line = 0;
}
Line &operator=(const Line &other) {
std::cout <<"go"<< endl;
delete[] line; //----------> purpose of using this delete??
line = new char[other.len()+1];
strcpy(line, other.line);
return *this;
}
int operator<=(const Line &other) {
int cmp = strcmp(line, other.line);
return cmp <= 0;
}
int len() const {
return strlen(line);
}
};
int main() {
Line array[] = {Line("abc"), Line("def"),
Line("xyz")};
Line tmp;
}
The delete inside the overloaded assignment operator is to clean the memory before assigning new memory(I have read it somewhere, correct me if I am wrong), but does this delete will call the destructor?
Please Explain
No, it will not.
This delete statement will delete the char array. The destructor of Line is only called when destroying the Line object. That is however not the case here.
The variable line and the object/class Line are different things.
The line variable is a member-variable in the Line class. So those two names seem the same but are completly different.
delete[] line; pairs the new char[strlen(s)+1]; statements in the constructor and assignment operator. Note that delete[] line; is a no-op if line is set to nullptr, which is what the else branch assignment does, although it sloppily uses 0 in place of nullptr.
Be assured the destructor is not called recursively. It's just that the destructor is used to release any allocated memory.
But using std::string line; as the class member variable, or perhaps even the entire class itself would be far, far easier. There are some subtle bugs in your code - self assignment being one of them, and the copy constructor is missing. Let the C++ Standard Library take care of all this for you. In short you could write
int main() {
std::string array[] = {"abc", "def", "xyz"};
std::string tmp;
}
The argument to delete[] is a char*, ie there is no destructor called (and also there is no recursive calling of the destructor).
If you had a destructor like this:
~Line() { delete this; } // DONT DO THIS !!! (also for other reasons it is not OK at all)
this would attempt to call itself recursively, but your code looks fine.
In the assignment operator
line = new char[other.len()+1];
will allocate new memory and assign a pointer (pointing to this memory) to line. This will cause that you have no handle to the old memory anymore and to avoid a leak you need to delete it before.
C++ by default takes care of delete[] for char*, therefore you do not need to do anything.
I know this is very basic but somehow working on different technologies I have mashed up my C++ concepts
I have created a simple program but it is giving exception when the destructor is called.
Below is the code:
#include "stdafx.h"
#include<iostream>
using namespace std;
class Employee
{
public:
Employee(char *name){
cout<<"Employee::ctor\n";
myName_p = new char(sizeof(strlen(name)));
myName_p = name;
}
void disp(){cout<<myName_p;}
~Employee()
{
cout<<"Employee:dtor\n\n";
delete myName_p;
}
private:
char *myName_p;
};
int main()
{
Employee emp("check");
emp.disp();
return(0);
}
Requesting all to clear this basic concept. As per my understanding we can't use delete[] because we are not using new[] in this case. Though I have tried using delete[] , but still it was giving error
You REALLY should use std::string here.
It is so much easier, especially for a beginner. The list of errors is:
you are calculating the wrong size of the name, it should be strlen(name)+1, not using sizeof anything.
You also should use new char[strlen(name)+1].
You are copying the data from the string supplied as the argument to the constructor, use strcpy rather than name_p = name - the latter leaks the memory you just allocated, and then you have a pointer to a const char * which you should not delete.
If you fix the allocation so that it is correct, you should then use delete [] name_p;.
However, it you instead use std::string, all of the above problems go away completely, you can just do:
Employee(char *name) name_p(name) { ... }
and get rid of all the problematic new, delete and copying. Of course, name_p is probably no longer a suitable name for the variable, but you get the idea.
Change
myName_p = new char(sizeof(strlen(name)));
myName_p = name;
to
myName_p = strdup(name);
and #include <cstring>. This creates new space and copies the parameter string. In this way, you'll have to call free instead of delete in your destructor.
Otherwise, after the second assignment, you have assigned the string literal "check" to myName_p, and the newly created space is discarded. Then your destructor tries to delete "check" rather than the allocated space, which results in crash.
Also, it is better practice to use std::string rather than old char* strings:
class Employee
{
public:
Employee(char *name): myName_p(name) {
cout<<"Employee::ctor\n";
}
void disp(){ cout << myName_p; }
private:
std::string myName_p;
};
The string class will manage memory for you.
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[].
I have a class that holds a few vectors, I'm not sure which method is the best but when the I call the destructor they should be deleted from memory.
HEADER:
class Test
{
public:
Test();
~Test();
void AddString(char* text);
void AddString(string text);
private:
char * StringToCharPointer(string value);
vector<char*> *pVector;
}
CPP File:
Test::Test()
{
};
Test::~Test()
{
vector<char*>::iterator i;
for ( i = pVector->begin() ; i < pVector->end(); i++ )
{
delete * i;
}
delete pVector;
};
char * Test::StringToCharPointer(string value)
{
char *pChar = new char[value.length()];
strcpy(pChar, value.c_str());
return pChar;
};
Test::AddString(char* text)
{
pVector->push_back(text);
};
Test::AddString(string text)
{
pVector->push_back(StringToCharPointer(text));
};
so here's pretty much all the methods that I use, but what's wrong?
Firstly, i is an iterator on the vector, it is not the pointer stored in the vector. *i is the pointer stored in the vector, so if you're going to delete anything it should be that.
Secondly, delete *i is only valid if the object pointed to by *i was allocated with new. Not new[], not malloc, and it doesn't point to a string literal. Since you don't say how your data was allocated, it is not possible for us to say whether or not you are freeing it correctly.
It seems likely that you should use a std::vector<std::string>.
Update for updated question:
HEADER:
class Test
{
public:
Test();
~Test();
void AddString(const string &text);
private:
vector<string> mVector;
};
CPP file:
Test::Test()
{
};
Test::~Test()
{
};
void Test::AddString(const string &text)
{
mVector.push_back(text);
};
Your destruction code looks fine (although I guess you meant delete *i; in the second snippet, since otherwise, ti wouldn't have even compiled.
However, the errors you are getting indicate you put bad things in your vectors. The only char*s that can be inserted in the vector with such destruction code are the ones returned by new char. Especially, you must not insert literals ("abc") or strings that are made as parts of other strings (strtok(NULL, ":"), strchr(str, ':') into it.
This is one obvious problem: char *pChar = new char[value.length()];. You are doing new[] but doing delete in destructor which invoked undefined behavior. You should use delete[] to delete those pointers. But using delete[] might give problems for Test::AddString(char* text) method as you can not be sure how memory for text is allocated i.e. using new or new[] or malloc. The simplest way is to use std::vector<std::string> as suggested by Steve Jossep.
It seems likely that you should use a std::vector<std::string>, to shorten the wise words of Steve Jessop.
To elaborate a little more: you say you want "to make the memory allocation smaller", but sounds like you're at the wrong path if you don't know pointers, and correct me if I'm wrong in guessing premature optimization (usually the case with inexperienced developers in this type of question).
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.