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.
Related
This question already has answers here:
Does returning a local variable return a copy and destroy the original(nrvo)?
(1 answer)
Shouldn't there be a copy ctor invocation here? Elision disabled (no named return value optimization)
(1 answer)
Closed 6 months ago.
In C++11, I have a class with a function that returns a new instance of that class. My clearly incorrect assumption was that if I constructed a new instance and returned it by value, the new instance would stay in scope. But I've learned that what I'm correctly observing is that its being destroyed like any other local variable. EDIT: My question is, what do I need to add or change to make a function instantiate an object and return it (without having it preallocated and passed in as a parameter)?
EDIT2: I've added move and copy constructors, and tried explicitly calling new Thingy instead of just having an instance variable. Still no change in behavior. I see the copy constructor called and then the destructor called when I invoke the function.
template<typename T>
class Thingy {
public:
// Constructor
Thingy(unsigned n) {
n_ = n;
}
// Move constructor
Thingy<T>(Thingy<T> && obj) {
cout << "Move constructor\n";
this->n_ = obj.n_;
}
// Copy constructor
Thingy<T>(const Thingy<T>& copy) {
cout << "Copy constructor\n";
this->n_ = copy.n_;
}
// Destructor
~Thingy() {
cout << "Destructor\n";
}
Thingy<T> dosomething() {
// Thingy<T> thing(n_); <-- this goes out of scope
Thingy<T>* thing = new Thingy<T>(n_); // I was hoping this would stay in scope, but no
...
return thing;
}
private:
unsigned n_;
In my main code I basically do:
Thingy<mytype> mainthing(10);
Thingy<mytype> anotherthing = mainthing.dosomething();
I can see that the destructor is being called and anotherthing is garbage.
What am I doing wrong/missing? Thanks!
This question already has answers here:
return type of the constructor in C++
(3 answers)
Closed 11 months ago.
All books and internet pages I read say that C++ constructors do not have a return value and they just initialize an object:
#include <iostream>
class Number {
int m_val{};
public:
Number() = default;
Number(int val) : m_val(val) {}
int val() { return m_val; }
};
int main() {
Number n; // Initializing object with defualt constructor
std::cout << n.val() << '\n';
return 0;
}
But it turns out that also I can use constructors for assignment and for calling methods of object, like it returns the value of this object:
Number n = Number(10); // This works
std::cout << Number(29).val() << '\n'; // And this
In other similar stackoverflow questions like this and this people write that this semantics creates a value-initialized temporary object of type Number , but it does not answer my question.
So does constructor return object, or maybe it is some c++ entity that i've never heard of?
Does C++ constructor return an object?
No, a constructor doesn't return anything. A constructor will be called when an object is created and the implicit this will point to the object that is being constructed.
P.S.
But it turns out that also I can use constructors for assignment and for calling methods of object, like it returns the value of this object:
Number n = Number(10);
That's not an assignment. That syntax of copy-initialisation.
Indeed a constructor doesn't have a return value.
But Number(10) is an object of type Number. And that is an expression with a value.
This question already has answers here:
Why does assignment operator call constructor?
(4 answers)
Closed 2 years ago.
Lets assume I have a program:
class A {
public:
A() { cout << '1'; }
A(int i) { cout << '2'; }
};
int main() {
A a;
a = 0;
return 0;
}
Result of this program will be 12.
So my question is - why am I able to call the second constructor through a = 0, when I already created the object and called the first constructor. I don't understand the whole concept of this. Isn't a constructor supposed to be called only once (during object creation)?
Isn't a constructor supposed to be called only once (during object creation)?
Yes, and that's what happens.
When you do a = 0;, the copy assignment operator A &operator=(const A &) gets called. Since the second operand is an int rather than an A, a new temporary instance of A is constructed, passed to the assignment operator, and then is destroyed right after it finishes.
The A(int) constructor allows implicit conversion from int to A.
So what happens with:
a = 0;
is really:
a = A(0);
If you want to disallow such implicit conversions, you need to make the constructor explicit:
explicit A(int);
This type of constructor is called "conversion constructor".
These type of constructors are used to perform implicit class-type conversions in C++.
Here you can find a little doc if you want to read.
This question already has answers here:
Why does the C++ map type argument require an empty constructor when using []?
(6 answers)
Closed 4 years ago.
class A
{
public:
A(int i)
{
x = new int(i);
}
~A()
{
if (x != NULL)
{
delete x;
x = NULL;
}
}
private:
A();
int *x;
};
void f()
{
{
map<int,A> myMap;
A a(2);
// myMap[7] = a; // cannot access default ctor
pair<int, A> p(7,a);
myMap.insert(p);
}
}
The problem here is that upon scope exit the destructor of A is called twice. Probably the first time to destruct A a(2) and the 2nd time to destruct some temp object created by map. This causes an exception since x is not allocated.
Why does the command myMap[7] = a construct a new A and why does it use the default ctor?
What can be a solution?
Because the subscript operator returns a reference to an element in the map, which you then assign to. In order to have an object to refer to, and assign to, that element must be constructed (unless an element already happens to exist for the given key).
a. To avoid the copy: emplace the A directly into the map instead of copying a local variable.
b. While getting rid of unnecessary copies is a good thing, it is not a substitute to fixing your class. Either make the class have well defined behaviour after assignment and copying, or make the class non copyable and non assignable. For more info, see rule of three (five).
You should never have bare owning pointers. Using a unique pointer instead would fix the class in an elegant way.
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;
}
};