It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I hava a class
class vlarray {
public:
double *p;
int size;
vlarray(int n) {
p = new double[n];
size = n;
for(int i = 0; i < n; i++)
p[i] = 0.01*i;
}
~vlarray() {
cout << "destruction" << endl;
delete [] p;
size = 0;
}
};
when I use in main
int main() {
vlarray a(3);
{
vlarray b(3);
b.p[0] = 10;
for(int i = 0; i < 3; i++) {
cout << *(b.p+i) << endl;
}
a = b;
} // the magic happens here deallocation of b
for(int i = 0; i < 3; i++) {
cout << *(a.p+i) << endl;
return 0;
}
when b deallocated smth happens to a .. what is the problem, why that problem occurs and how to avoid such type of problems?
There seems to be some confusion amongst the existing answers on this question, so I am going to jump in.
Immediate issue
Your primary issue is that you have not defined your own copy assignment operator. Instead, the compiler generates a naive one for you, so that when you run a = b, the pointer inside b is copied into a. Then, when b dies and its destructor runs, the pointer now inside a is no longer valid. In addition, a's original pointer has been leaked.
Your own copy assignment operator will need to delete the existing array, allocate a new one and copy over the contents from the object you're copying..
More generally
Going further, you will also need to define a few other things. This requirement is neatly summed-up as the Rule of Three (C++03) or Rule of Five (C++11), and there are plenty of explanations online and in your favourite, peer-recommended C++ book that will teach you how to go about satisfying it.
Or, instead...
Better still, you could start using an std::vector instead of manually allocating everything, and avoid this entire mess:
struct vlarray {
std::vector<double> p;
vlarray(int n) {
p.resize(n);
for(int i = 0; i < n; i++)
p[i] = 0.01*i;
}
};
You need to follow the Rule of Three in C++03 and Rule of Five in C++11.
Background and Basis of these Rules:
Whenever your class has an pointer member with an dynamic memory allocation, and whenever another object is created from this existing object by using any of the Copying Functions(Copy constructor & Copy Assignment Operator in c++03) unless you overload these two make a Deep Copy of the member pointer, the newly created object will keep pointing to the memory allocation of the parent object(Shallow Copy). The problem occurs when the parent object gets destroyed( for ex: by going out of scope) it's destructor gets called, which usually would free the memory allocated to the pointer member, When this happens the objects with a shallow copy of this pointer now point to invalid memory region and become Dangling Pointers. These dangling pointers when accessed result in Undefined Behavior and most likely crashes.
To avoid this you need to follow the Rule of Three in C++03 and Rule of Five in C++11.
The difference of Rules in C++03 and C++11 because the functions that control the copying behavior for a class have changed in C++11.
Rule of Three Basically states:
Implement the copy constructor, copy assignment operator and Destructor for your class.
EDIT:
If you are using C++11, then the Rule of Three actually becomes Rule of Five.
I think the problem is that you don't have a copy constructor. The compiler tried to do its best but it doesn't always succeed. Write a copy constructor and try again.
What you didn't implement is called:
Rule of three (C++ programming)
which in short says,
The rule of three (also known as the Law of The Big Three or The Big Three) is a rule of thumb in C++ that claims that if a class defines one of the following it should probably explicitly define all three:
destructor
copy constructor
copy assignment operator
Since you tagged your question C++11 as well, then you have to implement this:
Rule of Five (in C++11)
The destruction of b caused the member pointer p to be deleted. Since this pointer was copied to a, the member pointer of a is now pointing to deleted memory. You have undefined behavior.
To avoid this you need to do a deep copy at any point where you copy one object to another, typically the copy constructor and assignment operators. Allocate a new array and copy all the elements from one array to the other. You now adhere to the Rule Of Three because you've already defined a destructor.
The best way around this problem is to avoid raw pointers altogether and replace them with std::vector.
Direct asignment shares P between instances. Create a copy constructor.
When you assign b to a (a=b) the the compiler gerneated copy constructor does a shallow copy on your data members. I does not deference the pointers. So they both share the same resource, and when either of them are destroyed then they take their shared resource with them
Either define your own copy constructor to do a deep copy, or use an array abstraction like vector.
class vlarray {
public:
std::vector<double> p;
int size;
vlarray(int n) {
p.resize(n);
size = n;
for(int i = 0; i < n; i++) p[i] = 0.01*i;
}
~vlarray() {
cout << "destruction" << endl;
}
};
Related
I'm trying to understand section 4.6.2 of the book where move constructor and move assignment are introduced.
The way I understand it, the goal is to avoid a stack allocated vector to be needlessly copied (I'm speculating... on the heap or directly the call stack of the caller) before returning it to the caller. The code looks like so:
Vector operator+(const Vector& a, const Vector& b) {
if (a.size() != b.size())
throw length_error {"Vectors must be the same size"};
Vector res(a.size());
for (int i = 0; i < res.size(); i++)
res[i] = a[i]+b[i];
return res;
}
Here's my usage:
int main() {
Vector v1 {8,8,9};
Vector v3 = v1+v1+v1+v1;
cout << v3 << endl;
}
I have traces in my destructors and I would expect, without the usage of moving constructor/assignments, there to be additional destruction of the res local in operator+.
However there isn't, there is only one destruction that occurs on the subresult v1+v1 at the end of the program (this destruction has to occur since v1+v1 exists at a point in the program), one on the subresult of the former +v1, and then another one for the last +v1.
Also, implementing the moving constructor/assignment reveals that those are never called.
Why do I not see two destruction for each of the subresult without the moving constructor and why are my moving constructor not called when implemented?
I would wager that this is the result of copy elision. In short, the compiler is allowed to omit calling the copy/move constructors, even if they have side effects. So you cannot count on them being called
Relevant part from the reference says
Under the following circumstances, the compilers are required to omit
the copy and move construction of class objects, even if the copy/move
constructor and the destructor have observable side-effects. The
objects are constructed directly into the storage where they would
otherwise be copied/moved to.
Copy elision is an exception to the as-if rule, where compilers are only allowed to do optimizations that preserve the old behavior.
So I have to write an operator= method in c++ that copies all the values of one array into another. Here's what I wrote:
dynamic_array &dynamic_array::operator=(const dynamic_array &a) {
size = a.get_size();
if (size % BLOCK_SIZE == 0){ //a multiple of BLOCK_SIZE
allocated_size = size;
} else {
int full_blocks = size / BLOCK_SIZE;
allocated_size = (full_blocks+1) * BLOCK_SIZE;
}
try {
array = new int[allocated_size];
} catch (bad_alloc){
throw exception (MEMORY_EXCEPTION);
}
//copy a[i..size-1]
for (int i = 0; i < size; i++){
array[i] = a[i];
}
return *this; //returns a reference to the object
}
So it doesn't assume anything about the sizes and sets the size and allocated size of the array it's given (and using another get_size() method). Now the second code I have to write just says I have to create an array containing a copy of the elements in a. Now I just wrote the same thing as I did for my operator= method (without returning anything):
dynamic_array::dynamic_array(dynamic_array &a) {
size = a.get_size();
if (size % BLOCK_SIZE == 0){ //a multiple of BLOCK_SIZE
allocated_size = size;
} else {
int full_blocks = size / BLOCK_SIZE;
allocated_size = (full_blocks+1) * BLOCK_SIZE;
}
try {
array = new int[allocated_size];
} catch (bad_alloc){
throw exception (MEMORY_EXCEPTION);
}
//copy a[i..size-1]
for (int i = 0; i < size; i++){
array[i] = a[i];
}
}
Now this is giving me the output that I want but I'm just wondering if there's an easier way to do these two methods. The methods are for a dynamic array and I feel like there's more lines of code than needed. The operator= one is supposed to copy the elements of a into a new dynamic array and dynamic_array::dynamic_array(dynamic_array &a) { is supposed to create a new array containing a copy of the elements in a. It sounds like the same code for each method because you always need to create a new array and you will always need to copy the array elements from one array to another but is there a more simpler way to write these two methods or is this the simplest way to do it?
You could simplify both the copy constructor and the copy assignment operator by changing the type of array to std::vector<int>.
The vector does all the work for you and you don't even need any custom implementations at all.
First to make this simpler, you can make use of the fact that you have access to all private members of a. Also the use of memcpy will make this perform better. A couple of lines are added as well to delete the existing array before copying.
dynamic_array &dynamic_array::operator=(const dynamic_array &a) {
size = a.size;
allocated_size = a.allocated_size;
int* newArray = new int[allocated_size];
//copy array
memcpy(newArray, a.array, allocated_size * sizeof(int));
// Delete existing array
if (array != NULL)
delete[] array;
array = newArray;
return *this; //returns a reference to the object
}
Secondly, for copy constructor, a trick we used to do is to call the equal operator inside the copy constructor in order not to repeat the code:
dynamic_array::dynamic_array(dynamic_array &a) : array(NULL) {
*this = a;
}
From Scot Meyers (classic) book "Effective C++":
"In practice, the two copying functions will often have similar bodies, and this may tempt you to try to avoid code duplication by having one function call the other. Your desire to avoid code duplication is laudable, but having one copying function call the other is the wrong way to achieve it.
It makes no sense to have the copy assignment operator call the copy constructor, because you'd be trying to construct an object that already exists. This is so nonsensical, there's not even a syntax for it. There are syntaxes that look like you're doing it, but you're not; and there are syntaxes that do do it in a backwards kind of way, but they corrupt your object under some conditions. So I'm not going to show you any of those syntaxes. Simply accept that having the copy assignment operator call the copy constructor is something you don't want to do.
Trying things the other way around — having the copy constructor call the copy assignment operator — is equally nonsensical. A constructor initializes new objects, but an assignment operator applies only to objects that have already been initialized. Performing an assignment on an object under construction would mean doing something to a not-yet-initialized object that makes sense only for an initialized object. Nonsense! Don't try it.
Instead, if you find that your copy constructor and copy assignment operator have similar code bodies, eliminate the duplication by creating a third member function that both call. Such a function is typically private and is often named init. This strategy is a safe, proven way to eliminate code duplication in copy constructors and copy assignment operators."
And by the way, it'd be wise to also check for self-equality in you assignment operator.
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 7 years ago.
I have a question that how i can avoid the destruction in class.
I have the sample code C++ here:
class Array {
int *p;
int n;
public:
Array(int n_ = 0) {
p = new int[n_];
}
~Array(void) {
cout << "Deleted" << endl; delete []p;
}
friend Array operator+(Array A, Array B) // the amount of elements A and B are the same
{
Array S(A.n);
for(int i=0; i < A.n; i++)
S.p[i] = A.p[i] + B.p[i];
return S; // object S has been destroyed before returned.
}
};
In here, when the object has got the value and return. But object S have been destroyed by destruction before returned. Can anyone help me to avoid the destruction or some way for the object S can be returned to main. Thanks
You can either define a move and/or a copy constructor (if it is not implicitly defined) and the value will be moved/copied before its destruction.
You can provide a copy ctor, than it will turn out that your compiler never call it, due to NRVO (named Return Value Optimization).
Read this wiki: http://en.wikipedia.org/wiki/Return_value_optimization
With C++11 o C++14, you can use the move semantics, a general technique to move expensive objects.
My question is: is the following code about STL stack correct?
in the code, complex is a user defined class with constructor and destructor defined.
after place 1, complex constructor and destructor are called 5 times respectively,
and after place 2, complex destructor are called 5 times again due to pop().
so in total destructor are called more than constructor. IMO it should not happen.
Is my code correct? if not correct how to correct it? suppose I still use stack rather than stack
#include <stack>
#include "complex.h"
using namespace std;
void test_stack(){
stack<complex> mystack2;
cout << "Pushing complex..." << endl;
for (int i=0; i<5; ++i) {
complex c(i,i);
mystack2.push(c);
}
//place 1
cout << "Popping out complex..." << endl;
while (!mystack2.empty())
{
cout << " " << mystack2.top();
mystack2.pop(); //void pop();
}
//place 2
cout << endl;
}
To answer your original question, there is nothing wrong with your code. However, your understanding is a little off.
As others have noted, mystack2.push(c) will call the complex's copy constructor. So in total you have 5 calls to the constructor, 5 to the copy constructor, and 10 to the destructor.
This brings up a few important points. As you've noticed, the following code:
for (int i=0; i<5; ++i) {
complex c(i,i);
mystack2.push(c);
}
First creates a complex (c), then a copy is added to the stack, and the original complex is destroyed when c goes out of scope. In C++11, the extra copy is unnecessary, and you can do the following:
for (int i=0; i<5; ++i) {
mystack2.emplace(i, i);
}
Which will let the stack do the construction of the object, eliminating the need for a copy.
Another point which I think led to your confusion that the constructor was called 10 times, is that you said complex only defines a constructor and a destructor. If you don't define a copy constructor (and don't mark it private or deleted), one will be created automatically by the compiler. There's actually a little more to it than it with C++11, and I direct you to this question for details - Conditions for automatic generation of default/copy/move ctor and copy/move assignment operator?. The important thing to note, though, is that in this case your call to push was definitely calling a compiler-generated copy constructor.
You are probably not taking into account the copy constructor which would be called at
mystack2.push(c);
For value-type classes like complex, a copy constructor will be created for you automatically if you don't define your own.
You can create a copy constructor with something like this:
complex( complex const & other )
: real(other.real)
, imag(other.imag)
{
cout<<"complex::copy_constructor called"<<endl;
}
To simplify it, I won't mention that each of these happens 5 times:
complex c(i,i); - constructor called
mystack2.push(c); - constructor called
c falls out of scope - destructor called
mystack2.pop(); - destructor called
Note: To see what's going on add trace messages in the constructor and destructor. Don't forget the rule of three.
My professor in C++ has shown us this as an example in overloading the operator new (which i believe is wrong):
class test {
// code
int *a;
int n;
public:
void* operator new(size_t);
};
void* test::operator new(size_t size) {
test *p;
p=(test*)malloc(size);
cout << "Input the size of array = ?";
cin >> p->n;
p->a = new int[p->n];
return p;
}
Is this right?
It's definitely "not right", in the sense that it's giving me the creeps.
Since test has no user-declared constructors, I think it could work provided that the instance of test isn't value-initialized (which would clear the pointer). And provided that you write the corresponding operator delete.
It's clearly a silly example, though - user interaction inside an overloaded operator new? And what if an instance of test is created on the stack? Or copied? Or created with test *tp = new test(); in C++03? Or placement new? Hardly user-friendly.
It's constructors which must be used to establish class invariants (such as "I have an array to use"), because that's the only way to cover all those cases. So allocating an array like that is the kind of thing that should be done in a constructor, not in operator new. Or better yet, use a vector instead.
As far as the standard is concerned - I think that since the class is non-POD the implementation is allowed to scribble all over the data in between calling operator new and returning it to the user, so this is not guaranteed to work even when used carefully. I'm not entirely sure, though. Conceivably your professor has run it (perhaps many years ago when he first wrote the course), and if so it worked on his machine. There's no obvious reason why an implementation would want to do anything to the memory in the specific case of this class.
I believe that is "wrong" because he
access the object before the
constructor.
I think you're correct on this point too - casting the pointer returned from malloc to test* and accessing members is UB, since the class test is non-POD (because it has private non-static data members) and the memory does not contain a constructed instance of the class. Again, though, there's no reason I can immediately think of why an implementation would want to do anything that stops it working, so I'm not surprised if in practice it stores the intended value in the intended location on my machine.
Did some Standard checking. Since test has private non-static members, it is not POD. So new test default-initializes the object, and new test() value-initializes it. As others have pointed out, value-initialization sets members to zero, which could come as a surprise here.
Default-initialization uses the implicitly defined default constructor, which omits initializers for members a and n.
12.6.2p4: After the call to a constructor for class X has completed, if a member of X is neither specified in the constructor's mem-initializers, nor default-initialized, nor value-initialized, nor given a value during execution of the body of the constructor, the member has indeterminate value.
Not "the value its memory had before the constructor, which is usually indeterminate." The Standard directly says the members have indeterminate value if the constructor doesn't do anything about them.
So given test* p = new test;, p->a and p->n have indeterminate value and any rvalue use of them results in Undefined Behavior.
The creation/destruction of objects in C++ is divided into two tasks: memory allocation/deallocation and object initialization/deinitialization. Memory allocation/deallocation is done very differently depending on an object's storage class (automatic, static, dynamic), object initialization/deinitialization is done using the object's type's constructor/destructor.
You can customize object initialization/deinitialization by providing your own constructors/destructor. You can customize the allocation of dynamically allocated objects by overloading operator new and operator delete for this type. You can provide different versions of these operators for single objects and arrays (plus any number of additional overloads).
When you want to fine-tune the construction/destruction of objects of a specific type you first need to decide whether you want to fiddle with allocation/deallocation (of dynamically allocated objects) or with initialization/deinitialization. Your code mixes the two, violating one of C++' most fundamental design principle, all established praxis, every known C++ coding standard on this planet, and your fellow-workers' assumptions.
Your professor is completely misunderstanding the purpose of operator new whose only task is to allocate as much memory as was asked and to return a void* to it.
After that the constructor is called to initialize the object at that memory location. This is not up to the programmer to avoid.
As the class doesn't have a user-defined constructor, the fields are supposed to be uninitialized, and in such a case the compiler has probably freedom to initialize them to some magic value in order to help finding use of uninitialized values (e.g for debug builds). That would defeat the extra work done by the overloaded operator.
Another case where the extra work will be wasted is when using value-initialization: new test();
This is very bad code because it takes initialization code that should be part of a constructor and puts it in operator new which should only allocate new memory.
The expression new test may leak memory (that allocated by p->a = new int[p->n];) and the expression new test() definitely will leak memory. There is nothing in the standard that prevents the implementation zeroing, or setting to an alternate value, the memory returned by a custom operator new before that memory is initialized with an object even if the subsequent initialization wouldn't ordinarily touch the memory again. If the test object is value-initialized the leak is guaranteed.
There is also no easy way to correctly deallocate a test allocated with new test. There is no matching operator delete so the expression delete t; will do the wrong thing global operator delete to be called on memory allocated with malloc.
This does not work.
Your professor code will fail to initialize correctly in 3/4 of cases.
It does not initialize objects correctly (new only affects pointers).
The default constructor generated for tests has two modes.
Zero Initialization (which happens after new, but POD are set to zero)
Default Initialization (POD are uninitialized)
Running Code (comments added by hand)
$ ./a.exe
Using Test::new
Using Test::new
A Count( 0) // zero initialized: pointer leaked.
A Pointer(0)
B Count( 10) // Works as expected because of default init.
B Pointer(0xd20388)
C Count( 1628884611) // Uninitialized as new not used.
C Pointer(0x611f0108)
D Count( 0) // Zero initialized because it is global (static storage duration)
D Pointer(0)
The Code
#include <new>
#include <iostream>
#include <stdlib.h>
class test
{
// code
int *a;
int n;
public:
void* operator new(size_t);
// Added dredded getter so we can print the values. (Quick Hack).
int* getA() const { return a;}
int getN() const { return n;}
};
void* test::operator new(size_t size)
{
std::cout << "Using Test::new\n";
test *p;
p=(test*)malloc(size);
p->n = 10; // Fixed size for simple test.
p->a = new int[p->n];
return p;
}
// Objects that have static storage duration are zero initialized.
// So here 'a' and 'n' will be set to 0
test d;
int main()
{
// Here a is zero initialized. Resulting in a and n being reset to 0
// Thus you have memory leaks as the reset happens after new has completed.
test* a = new test();
// Here b is default initialized.
// So the POD values are undefined (so the results are what you prof expects).
// But the standard does not gurantee this (though it will usually work because
// of the it should work as a side effect of the 'zero cost principle`)
test* b = new test;
// Here is a normal object.
// New is not called so its members are random.
test c;
// Print out values
std::cout << "A Count( " << a->getN() << ")\n";
std::cout << "A Pointer(" << a->getA() << ")\n";
std::cout << "B Count( " << b->getN() << ")\n";
std::cout << "B Pointer(" << b->getA() << ")\n";
std::cout << "C Count( " << c.getN() << ")\n";
std::cout << "C Pointer(" << c.getA() << ")\n";
std::cout << "D Count( " << d.getN() << ")\n";
std::cout << "D Pointer(" << d.getA() << ")\n";
}
A valid example of what the professor failed to do:
class test
{
// code
int n;
int a[1]; // Notice the zero sized array.
// The new will allocate enough memory for n locations.
public:
void* operator new(size_t);
// Added dredded getter so we can print the values. (Quick Hack).
int* getA() const { return a;}
int getN() const { return n;}
};
void* test::operator new(size_t size)
{
std::cout << "Using Test::new\n";
int tmp;
std::cout << How big?\n";
std::cin >> tmp;
// This is a half arsed trick from the C days.
// It should probably still work.
// Note: This may be what the professor should have wrote (if he was using C)
// This is totally horrible and whould not be used.
// std::vector is a much:much:much better solution.
// If anybody tries to convince you that an array is faster than a vector
// The please read the linked question below where that myth is nailed into
// its over sized coffin.
test *p =(test*)malloc(size + sizeof(int) * tmp);
p->n = tmp;
// p->a = You can now overflow a upto n places.
return p;
}
Is std::vector so much slower than plain arrays?
As you show this is wrong. You can also see how easy it is to get this wrong.
There usually isn't any reason for it unless you are trying to manage your own memory allocations and in a C++ environment you would be better off learning the STL and write custom allocators.