I am trying to understand the concept of copy constructor. I used this example:
#include <iostream>
using namespace std;
class Line
{
public:
int GetLength();
Line(int len);
Line(const Line &obj);
~Line();
private:
int *ptr;
};
Line::Line(int len)
{
ptr = new int;
*ptr = len;
};
Line::Line(const Line &obj)
{
cout << "Copying... " << endl;
ptr = new int;
*ptr = *obj.ptr;
};
Line::~Line()
{
delete ptr;
};
int Line::GetLength()
{
return *ptr;
}
int main()
{
Line line1 = Line(4);
cout << line1.GetLength() << endl;
Line line2 = line1;
line1.~Line();
cout << line2.GetLength() << endl;
return 0;
}
The question is, why do I get runtime error here? If I defined a copy constructor which allocates memory for the new ptr, and assigned the line1 to line2, doesn't that mean that those two are separate objects? By destructing line1, I obviously mess up line2 as well, or am I using the destructor call wrong?
You called the destructor in this statement
line1.~Line();
which deleted the memory allocated for ptr
Line::~Line()
{
delete ptr;
};
However the object line1 is alive because it has automatic storage duration. So after exiting main the destructor for the object will be called one more and as result it will try to delete the memory pointed to by ptr that was already deleted explicitly.
line1.~Line();
Manually calling a destructor is useful only if you use placement new.
I don't understand what gave you the idea to call the destructor manually in this program. You don't really want to know such a low-level memory-management mechanism when you are still new to the language, but for the sake of completeness, it would work like this:
int main()
{
// provide static memory with enough space for one Line object:
char buffer[sizeof(Line)];
// create a Line object and place it into buffer:
Line* line1 = new (buffer) Line(4);
cout << line1->GetLength() << endl;
Line line2 = *line1;
// manually call the destructor:
line1->~Line();
cout << line2.GetLength() << endl;
// - no delete necessary because buffer disappears automatically
// - no automatic destructor call
return 0;
}
Your code, however, results in an attempt to call the destructor of line1 twice. First manually, then automatically when the object's scope ends, i.e. at the end of main. This is undefined behaviour. See Does explicitly calling destructor result in Undefined Behavior here?
The question is, why do I get runtime error here?
Because undefined behaviour means that your program can do or not do anything. The runtime error is not guaranteed, nor are you guaranteed any deterministic behaviour at all.
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'm trying to make this code work, but the object keep getting destroyed...
I've found that it has to do with the object being copied to the vector, but can't find any way to prevent it...
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Obje
{
private:
static int instances;
int id;
public:
static int getInstances();
void getId();
virtual void myClass();
Obje(int auxId);
~Obje();
};
int Obje::instances = 0;
int Obje::getInstances()
{
return instances;
}
Obje::Obje(int auxId)
{
this->id = auxId;
cout << "Obje Created." << endl;
Obje::instances++;
}
Obje::~Obje()
{
cout << "Obje Destroyed." << endl;
Obje::instances--;
}
void Obje::myClass()
{
cout << "Obje." << endl;
}
void Obje::getId()
{
cout << this->id << endl;
}
int main()
{
vector <Obje> list;
Obje *a = new Obje(59565);
list.push_back(*a);
Obje *b = new Obje(15485);
list.push_back(*b);
for(vector<Obje>::iterator it = list.begin(); it != list.end(); ++it)
{
it->getId();
}
return 0;
}
It Generates this output:
Obje Created.
Obje Created.
Obje Destroyed.
59565
15485
Obje Destroyed.
Obje Destroyed.
What does it mean the T(const T& new); i've saw as fix for this?
First of all, it is a bad practice to allocate an object in heap without using smart pointers and forgetting to delete it. Especially, when you are creating it just to make a copy of it.
list.push_back(*a); creates a copy of *a in vector. To create an item in vector without copying another item, you can do list.emplace_back(/*constructor parameters*/);, which is available from c++11. (see http://en.cppreference.com/w/cpp/container/vector/emplace_back)
So, to make the result behavior match your expectations, you should go
vector <Obje> vec;
vec.emplace_back(59565);
vec.emplace_back(15485);
for(const auto & item : vec)
{
item.getId();
}
By the way, it is also a quite bad practice to call a vector as a list, as a list is a different container type and reading such code may be confusing a bit. I guess, I am starting being annoying, but it is better to call method getId as showId as now it returns nothing.
Regarding the use of heap, new and pointer, see my comment in your question.
Regarding the issue object was destroyed, the vector maintains an internal buffer to store object. When you push_back new object to the vector, if its internal buffer is full, it will (the stuff which will be executed when exception occurs won't be mentioned here.):
allocate new internal buffer which is big enough to store its new data.
move data from old internal buffer to new internal buffer.
destroy old buffer.
Hence, your object will be destroyed and copied to new location in this case, hence copy constructor will make it clearer to you.
P/S: AFAIK, some compilers move its data by memmove or std::move
Ignoring usefulness of such practice. (Though real-life examples are welcome, of course.)
For example, the following program outputs the correct value for a:
#include <iostream>
using namespace std;
int main()
{
int a = 11111;
int i = 30;
int* pi = new (&i) int();
cout << a << " " << endl;
}
But isn't new-allocation supposed to create some bookkeeping information adjacent to i (for correct subsequent deallocation), which in this case is supposed to corrupt the stack around i?
Yes, it's perfectly OK to perform placement-new with a pointer to an object on the stack. It will just use that specific pointer to construct the object in. Placement-new isn't actually allocating any memory - you have already provided that part. It only does construction. The subsequent deletion won't actually be delete - there is no placement delete - since all you need to do is call the object's destructor. The actual memory is managed by something else - in this case your stack object.
For example, given this simple type:
struct A {
A(int i)
: i(i)
{
std::cout << "make an A\n";
}
~A() {
std::cout << "delete an A\n";
}
int i;
};
The following is completely reasonable, well-behaved code:
char buf[] = {'x', 'x', 'x', 'x', 0};
std::cout << buf << std::endl; // xxxx
auto a = new (buf) A{'a'}; // make an A
std::cout << a->i << std::endl; // 97
a->~A(); // delete an A
The only case where this would be invalid would be if your placement-new-ed object outlasts the memory you new-ed it on - for the same reason that returning a dangling pointer is always bad:
A* getAnA(int i) {
char buf[4];
return new (buf) A(5); // oops
}
Placement new constructs the element in place and does not allocate memory.
The "bookkeeping information" in this case is the returned pointer which ought to be used to destroy the placed object.
There is no delete associated with the placement since placement is a construction. Thus, the required "clean up" operation for placement new is destruction.
The "usual steps" are
'Allocate' memory
Construct element(s) in place
Do stuff
Destroy element(s) (reverse of 2)
'Deallocate' memory (reverse of 1)
(Where memory can be stack memory which is neither required to be explicitly allocated nor deallocated but comes and goes with a stack array or object.)
Note: If "placing" an object into memory of the same type on the stack one should keep in mind that there's automatic destruction at the end of the object's lifetime.
{
X a;
a.~X(); // destroy a
X * b = new (&a) X(); // Place new X
b->~X(); // destroy b
} // double destruction
No, because you don't delete an object which has been placement-newed, you call its destructor manually.
struct A {
A() { std::cout << "A()\n"; }
~A() { std::cout << "~A()\n"; }
};
int main()
{
alignas(A) char storage[sizeof(A)];
A *a = new (storage) A;
std::cout << "hi!\n";
a->~A();
std::cout << "bye!\n";
}
Output:
A()
hi!
~A()
bye!
In your case, there's no need to call a destructor either, because int is trivially-destructible, meaning that its destructor would be a no-op anyway.
Beware though not to invoke placement-new on an object that is still alive, because not only will you corrupt its state, but its destructor will also be invoked twice (once when you call it manually, but also when the original object should have been deleted, for exampel at the end of its scope).
Placement new does construction, not allocation, so there's no bookkeeping information to be afraid of.
I can at the moment think of one possible use case, though it (in this form) would be a bad example of encapsulation:
#include <iostream>
using namespace std;
struct Thing {
Thing (int value) {
cout << "such an awesome " << value << endl;
}
};
union Union {
Union (){}
Thing thing;
};
int main (int, char **) {
Union u;
bool yes;
cin >> yes;
if (yes) {
new (&(u.thing)) Thing(42);
}
return 0;
}
Live here
Though even when the placement new is hidden in some member function, the construction still happens on the stack.
So: I didn't look in the standard, but can't think of why placement new on the stack shouldn't be permitted.
A real world example should be somewhere in the source of https://github.com/beark/ftl ... in their recursive union, which is used for the sum type.
What is the difference between these two instantiation and method call types?
Take this code for example:
class Test
{
public:
Test(int nrInstance)
{
std::cout << "Class " << nrInstance << " instanced " << std::endl;
}
~Test() { }
int retornaValue()
{
return value;
}
private:
const int value = 10;
};
int main(int argc, char *argv[])
{
Test *test1 = new Test(1);
Test test2(2);
std::cout << test1->retornaValue() << std::endl;
std::cout << test2.retornaValue() << std::endl;
return 0;
}
From what ive read, using the first way, the variable is allocated in the heap, and the second, in the stack, but arent both inside the Main scope, and being deallocated after the function exits?
Also, calling methods is different in both examples, why?
Your right that both variables are in the Main scope and deallocated after the function exits, but in the first case it is the Test* value that is deallocated, not the Test instance itself. Once the pointer is deallocated, the class instance is leaked. In the second case, the Test instance is on the stack, so the instance itself is deallocated.
Also, calling methods is different in both examples, why?
Unless overloaded, foo->bar is equivalent to (*foo).bar. The calling syntax is different because in the first case, test1 is a pointer to an instance, and in the second, test2 is an instance.
but arent both inside the Main scope, and being deallocated after the
function exits?
No not at all... *test1 will not be deallocated until you call delete on it.
but arent both inside the Main scope, and being deallocated after the function exits?
The stack instance is unwound as the scope is closed, and thus deallocated. The pointer is as well, but the object it points to is not. You must explicitly delete instances allocated with new.
In the first example, you are creating both a pointer to the object on the stack, and the object itself on the heap.
In the second example you are creating the object itself on the stack.
The syntax difference is the difference between calling a function through a pointer and calling it on an object directly.
You are wrong about the first example being cleaned up, you need a delete before the pointer goes out of scope or you have what is known as a memory leak. Memory leaks will be cleaned up by the OS when the program exits, but good practice is to avoid them.
You've clearly stated the difference in your question, one is on the stack, and one is on the heap. And yes, when main() exits, it will be deallocated. Now let's take a different approach.
#include <iostream>
using namespace std;
class MemoryLeak{
private:
int m_instance
public:
MemoryLeak(int i) : m_instance(i)
{ cout << "MemoryLeak " << i << " created.\n"; }
~MemoryLeak() { cout << "MemoryLeak " << m_instance << " deleted.\n"; }
};
void makeMemoryLeak(){
static int instance = 0
MemoryLeak mem1(++instance);
MemoryLeak* mem2 = new MemoryLeak(++instance);
}
int main(){
for(int x = 0; x < 10; ++x){
makeMemoryLeak();
cout << endl;
}
cin.get(); // Wait to close
return 0;
}
You will see 20 "New MemoryLeak created." lines but only 10 "MemoryLeak deleted" lines. So those other 10 instances are still in memory until you close the program. Now let's say that that program never shuts down, and MemoryLeak has a size of 20 bytes. and makeMemoryLeak() runs once a minute. After one day, or 1440 minutes, you'll have 28.125 kb of memory that is taken up, but you have no way to access.
The solution would be to change makeMemoryLeak()
void makeMemoryLeak(){
MemoryLeak mem1;
MemoryLeak* mem2 = new MemoryLeak();
delete mem2;
}
Regarding what gets created and destroyed:
struct Test {};
void func()
{
// instantiate ONE automatic object (on the stack) [test1]
Test test1;
// Instantiate ONE automatic object (on the stack) [test2]
// AND instantiate ONE object from the free store (heap) [unnamed]
Test* test2 = new Test; // two objects!!
} // BOTH automatic variables are destroyed (test1 & test2) but the
// unnamed object created with new (that test2 was pointing at)
// is NOT destroyed (memory leak)
if you dont delete Test1 (Test*) before coming out of main, it will cause memory leak.
Consider the program below. It has been simplified from a complex case. It fails on deleting the previous allocated memory, unless I remove the virtual destructor in the Obj class. I don't understand why the two addresses from the output of the program differ, only if the virtual destructor is present.
// GCC 4.4
#include <iostream>
using namespace std;
class Arena {
public:
void* alloc(size_t s) {
char* p = new char[s];
cout << "Allocated memory address starts at: " << (void*)p << '\n';
return p;
}
void free(void* p) {
cout << "The memory to be deallocated starts at: " << p << '\n';
delete [] static_cast<char*> (p); // the program fails here
}
};
struct Obj {
void* operator new[](size_t s, Arena& a) {
return a.alloc(s);
}
virtual ~Obj() {} // if I remove this everything works as expected
void destroy(size_t n, Arena* a) {
for (size_t i = 0; i < n; i++)
this[n - i - 1].~Obj();
if (a)
a->free(this);
}
};
int main(int argc, char** argv) {
Arena a;
Obj* p = new(a) Obj[5]();
p->destroy(5, &a);
return 0;
}
This is the output of the program in my implementation when the virtual destructor is present:
Allocated memory address starts at: 0x8895008
The memory to be deallocated starts at: 0x889500c
RUN FAILED (exit value 1)
Please don't ask what the program it's supposed to do. As I said it comes from a more complex case where Arena is an interface for various types of memory. In this example the memory is just allocated and deallocated from the heap.
this is not the pointer returned by the new at line char* p = new char[s]; You can see that the size s there is bigger than 5 Obj instances. The difference (which should be sizeof (std::size_t)) is in additional memory, containing the length of the array, 5, immediately before the address contained in this.
OK, the spec makes it clear:
http://sourcery.mentor.com/public/cxx-abi/abi.html#array-cookies
2.7 Array Operator new Cookies
When operator new is used to create a new array, a cookie is usually stored to remember the allocated length (number of array elements) so that it can be deallocated correctly.
Specifically:
No cookie is required if the array element type T has a trivial destructor (12.4 [class.dtor]) and the usual (array) deallocation function (3.7.3.2 [basic.stc.dynamic.deallocation]) function does not take two arguments.
So, the virtual-ness of the destructor is irrelevant, what matters is that the destructor is non-trivial, which you can easily check, by deleting the keyword virtual in front of the destructor and observe the program crashing.
Based on chills' answer, if you want to make it "safe":
#include <type_traits>
a->free(this - (std::has_trivial_destructor<Obj>::value ? 1 : 0));