The question is how to correctly delete name in A destructor?
class A{
private:
char *name;
public:
A(char *n) : name(n) {}
~A(){
//???
}
}
int main(){
A *a = new A("name");
delete a;
return 0;
}
Given that you do not change the constructor, then the correct way is to not delete anything. Ownership of the string belongs to the client, since you are not creating a copy.
However, the right way of rewriting this is to let the constructor allocate a copy of the string with new[] and let the destructor deallocate it with delete[].
And the really right way is to let std::string do the whole thing for you, and not write an explicit destructor at all:
#include <string>
class A{
private:
std::string name;
public:
A(std::string n) : name(std::move(n)) {}
};
This, by the way, allows you not to worry about the Rule of Three, which means you won't have to bother writing a copy constructor, a move constructor, a copy assignment operator, a move assignment operator, a destructor and whatnot.
You are not allowed to delete a pointer to string constant "name".
As your class does not own any objects or memory blocks, it should not delete anything.
In this example you don't need to delete name. "name" is just a pointer to some some place in executable image, not memory allocated with new/malloc/something_else.
"name" occupies static memory that the compiler automatically sets aside. If you delete that memory, the behavior is undefined (i.e. crash). You only 'delete' memory that you 'new' in the first place.
The simplest thing is to use proper C++ (std::string) and avoid naked pointers, as that simplifies management of resources.
The problem with your interface is that the type A claims ownership of the argument, but you cannot claim ownership of a string literal, as those are managed by the implementation. You could go on trying to decide whether the caller should create deep copy and pass it to a A or if A design should be changed not to attempt to claim ownership and make a copy out of that. But the fact is that things are much simpler if you just use higher level constructs:
class A {
std::string name;
public:
A(const std::string& name) : name(name) {}
};
No need to manually copy data around, no need for a destructor or a copy constructor... all works out of the box.
Related
I have difficulty understanding std::move behavior and would like to know whether it is necessary to manually call delete for newStudentDan after "addStudent" in an example like below, or it will be a memory leak.
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Student {
public:
Student(std::string name): name_{name} {}
void addParent(std::string name) {
parent_ = name;
}
private:
std::string name_;
std::string parent_;
};
class School {
public:
//constructor
School(): name_{"default"} {}
Student* addStudent(Student student);
Student* addStudent(std::unique_ptr<Student>&& ptr, int);
private:
std::string name_;
std::vector<std::unique_ptr<Student>> students_;
};
Student* School::addStudent(Student student) {
return this->addStudent(std::unique_ptr<Student>{ new Student{std::move(student)}}, 1);
}
Student* School::addStudent(std::unique_ptr<Student>&& ptr, int) {
Student* retval{ptr.get()};
students_.push_back(std::move(ptr));
return retval;
}
int main() {
School newSchool;
Student* newStudentDan = new Student("Dan");
newStudentDan->addParent("Lisa");
newSchool.addStudent(*newStudentDan);
//...continues
return 0;
}
I think your confusion stems from two related, but separate concepts: storage duration and object lifetime. Moving an object, just like copying, causes a new object to be created, without ending the lifetime of the original. On the other hand, a memory leak is a failure to deallocate memory that is no longer needed, which is indeed the case with newStudentDan in your example.
The direct answer to your question is that yes, you should always delete any object allocated with new, regardless of what you do with it.
Move semantics can be demonstrated without the use of dynamic allocations:
Student& School::addStudent(Student student) {
students_.push_back(std::move(student));
return students_.back();
}
int main() {
School newSchool;
Student newStudentDan {"Dan"};
newStudentDan.addParent("Lisa");
newSchool.addStudent(std::move(newStudentDan));
}
Perhaps the easiest way to think about it is this: std::move does not actually move anything, it allows the compiler to select functions that may "steal" the object's resources, such as by invoking its move constructor or move-assignment operator. These may not be available, in which case the copy operations are used if available.
In the snippet above, Student has an (implicit) move constructor, so it will be the one used to create the new object from newStudentDan. The lifetime of newStudentDan continues until the end of main() and it will still have some memory associated with it, even though its actual data are now owned by the vector. But because it's now a stack variable (it has "automatic storage duration"), destruction and deallocation occur automatically.
Note that not even move constructors do any moving either, in the sense of relocating data in memory. For example, as this detailed answer explains, the move constructor for std::unique_ptr simply copies a pointer and sets the source pointer to nullptr, without touching the object itself. For better or worse, the word "move" is just a term that indicates the type of semantics where the source object will not necessarily be equivalent to the target object.
I have the following code snippet:
#include <iostream>
using namespace std;
class A {
int* data;
int size;
public:
A(int s):size(s)
{
data = new int[size];
}
A() {
data = nullptr;
}
~A() {
if (data) delete [] data;
}
};
class B {
A a[2];
public:
B() {
a[0] = A(10);
a[1] = A(11);
}
};
int main(int argc, char *argv[]) {
B b;
}
In the C++ code above, I have class A which has an array member int* data, and the (de)allocation of memory are handled by (de)constructor. The I created class B which has an array of class A of fixed length as a data member.
My question is: how to elegantly initialise the member A a[2]? In the code above, the A(10) and A(11) are created on the stack, when jumping out of the scope, their destructors will be called, hence the data comes invalid. When jumping of the main function's scope, the pointers held by a[2] will be deallocated twice, causing the error:
pointer being freed was not allocated.
One possible solution is to carefully design a copy constructor and a move constructor, by doing so the above coding paradigm could work.
Another solution I've tried is to initialise the array in the initialization list of class B:
B() : a { A(10), A(11) }
This solution works and I don't really tell the underlying mechanism of initialization list. I think it must be quite different from simply construct and copy. I really expected some experts could give an elaborate explanation of this mechanism. Of course, this solution is ugly hard-coded and not flexible.
So I wonder if there are some programming paradigms in C++ to tackle this design problem?
In the code above, the A(10) and A(11) are created on the stack
They are temporary objects. It is not specified where they are created or if they're created at all.
when jumping out of the scope, their destructors will be called
The destructor of each temporary will be called after the corresponding move assignment statement ends.
One possible solution is to carefully design a copy constructor and a move constructor, by doing so the above coding paradigm could work.
And {copy,move} assignment operator too. You should always do that when the implicitly declared ones don't do the right thing. And they never do the right thing if you delete something in the destructor.
Another solution I've tried is to initialise the array in the initialization list of class B
This solution works and I don't really tell the underlying mechanism of initialization list. I think it must be quite different from simply construct and copy.
The bug in the original code is badly behaving move assignment operator of A. Since the initialization list never move assigns from a temporary, it never triggers the bug.
This is actually the more elegant way to construct a that you asked for. Not because it avoids the bug, but because avoiding unnecessary moving is good thing, intrinsically.
So I wonder if there are some programming paradigms in C++ to tackle this design problem?
Yes. RAII and Single responsibility principle. Unless your class does nothing else, besides managing the memory pointed by data, it should not be managing the memory. Instead, it should delegate the memory management to a RAII object. In this case, you should use a std::vector member.
class A {
std::vector<int> data;
public:
A(int s):data(s) {}
A() = default;
};
Using an initializer list to construct B::a, like this:
class B {
A a[2];
public:
B() : a({10, 11}){
}
};
The ideal answer would be to force A to use movements instead of copies, or on a copy to allocate new space for the item. Of the two, the most efficient is the former and so I will expand on it below:
Forcing movement can be done in two fashions:
Delete the copy constructor and copy operator=, and implement your own move constructor and operator=
Consistently use std::move and std::swap.
Of these, the former is superior in that you will be unable to accidentally copy the class, but with the latter the fact that you are moving will be more evident.
To delete the default copy methods do:
class A {
A( const A& a ) = delete;
A& operator =( const A& a ) = delete;
}
I've got a project in C++ that uses classes(quite basic elements).
My class looks like this:
class vehicule: public frane,public motor,public directie,public noxe,public caroserie
{
char tip[40];
int placfatacant,placfatatot;
static const int placfatapret=18;
int placspatecant,placspatetot;
static const int placspatepret=15;
public:
vehicule()
void settip(char)
void verifauto()
;};
I've been told I have to use copy constructor and destructor. I have some examples,but both use dynamic allocation. Now my question is:what should my copy constructor/destructor do as I don't have dynamic allocated memory to copy/delete? Or should I declare the data as
int *placfatacant
and then use
delete placfatacant
?
Thanks in advance!
You only need to declare a constructor if you need to handle the deletion of dynamically allocated variables, as you said. In general, for every new, there must be a delete.
I don't see any new'd objects in your class, so I would just let the compiler-generated destructor/copy constructor do its thing. Your class is entirely statically allocated and will be deleted when it falls out of scope of the context in which it is used.
If it is for school purpose you can change :
// From:
char tip[40];
// To:
char * tip;`
And then in your constructor you will make:
tip = new char[40]();
Now you have to create a copy constructor like this one:
vehicule(const vehicule & toCopy)
{
tip = new char[40]();
strcpy(tip, toCopy.tip);
}
Your destructor just need to deallocate tip:
~vehicule()
{
delete tip;
}
Is the following assignment valid?
class A {
int a;
public:
A(int k): a(k){}
}
void main() {
A first (5);
A second;
second = first;
}
If it is valid, what happens for second? Does C++ makes a deep copy? Or a shallow copy?
Perhaps you are new to C++, perhaps a student?
You are lucky, since the data member for your A class is an integer. Which is a plain old data type. Called POD for short. BTW: You tagged your question with copy-constructor, but demonstrated in your example an assignment operator.
They are two different things.
A copy constructor makes a new instance based off of another instance. Like this:
class A
{
public:
A(A& other) { ... }
};
An assignment operator looks like this:
class A
{
public:
const A& operator=(const A& other) { ... }
};
Since you did not provide your own assignment operator, the compiler made one for you. In fact the compiler will also make a destructor for you too. Isn't that nice? Well don't always trust your compiler. If your classes have anything beyond Plain old Data, then please get in the habit of providing your own constructors, destructors, assignment operators. It's a rule I live by. I'd hate to have a bug that takes 2 days to track down to say... a memory leak due to my forgetting to deallocate memory in a destructor.
In your case, the compiler made a shallow copy for you. A compiler will never make a deep copy for you. You have to do that yourself.
Since you wrote one form of constructor, compiler will not provide default constructor so your declaration 'A second;' will not compile. You could possibly do A second(0); and then second = first;
Sorry about the title. I wasnt sure what to name it. If any mods are reading and they understand the question then please rename if needed too.
Say you create a new variable (varOne).
Inside the varOne code, other variables are created as new (varTwo, varThree).
If you call delete on varOne, will varTwo and varThree be deleted, or do you need to delete them AND delete varOne?
You only need to delete varTwo and varThree, because when you fall out of varOne's destructor, the delete you used to invoke varOne's destructor will clean up that instance of varOne.
In other words, in the example below, varOne is Foo, varTwo is m_i, and varThre is m_c:
class Foo
{
public:
Foo() : m_i( new int ), m_c( new char ) { }
~Foo() { delete m_i; delete m_c; }
// don't forget to take care of copy constructor and assignment operator here!!!
private:
int* m_i;
char* m_char;
};
main()
{
Foo* p = new Foo;
delete p;
}
Also make sure that when you do this, you follow The Rule of Three or your program will suffer memory problems. (In other words, if you are doing memory allocation in your constructor, be sure you either override or delete the default copy-constructor and assignment operators).
You have to delete them and delete varOne seperately, but actually the constructor of varOne should allocate those variables and the destructor should deallocate them if they have to be on the heap for some reason. It would be better to just store them by value and be rid of new and delete for good.
I'm not 100% sure what you mean, but in general, anything that you allocate with new, you have to individually deallocate with delete.
If you mean this in the context of a C++ class, you will need to manually delete varOne and varTwo of the destructor.
Use a smart pointer, and never ever ever delete anything in your own code.
I'm not sure how to understand your question, since you don't new a variable (all variables are static, automatic or member variables) but objects (the pointers you get from new will however usually assigned to use used to initialize variables, maybe that's what you meant?). Therefore I'll give a general answer ad hope that what you asked for is included.
First, as a basic rule, every object you allocate with new has to be deallocated explicitly with delete. However, the delete might be hidden in another object, like shared_ptr and scoped_ptr/unique_ptr from boost or C++11, or auto_ptr in earler versions of C++.
If your object contains subobjects, it's usually best to make them direct members, so you don't allocate them with new at all (indeed, that's a general rule in C++: If you don't absolutely have to dynamically allocate, don't). That is, you'd write your class as
class X
{
public:
// ...
private:
Type1 subobject1;
Type2 subobject2:
};
and don't have to mess with new/delete for the sub objects at all. However if you need to dynamically allocate the objects, you also have to delete them, e.g.
class X
{
public:
X()
{
subobject1 = new Type1();
try
{
subobject2 = new Type2();
}
catch(...)
{
delete subobject1;
}
}
~X()
{
delete subobject2;
delete subobject1;
}
// ...
private:
X(X const&); // disabled
X& operator=(X const&); // disabled
Type1* subobject1;
Type2* subobject2;
};
Note the rather complicated code in X's constructor to make sure the object is correctly cleaned up even in case of an exception. Also note that you also have to implement copy construction and assignment or disable them by making them private and unimplemented (note that C++11 offers the special syntax = delete to disable them). You can save yourself a lot of the trouble by using a smart pointer (but you still have to take care about copy construction and assignment, at least with the usual smart pointers):
class X
{
public:
X():
subobject1(new Type1()),
subobject2(new Type2())
{
}
private:
X(X const&) = delete; // disabled
X& operator=(X const&) = delete; // disabled
std::unique_ptr<Type1> subobject1;
std::unique_ptr<Type2> subobject2;
};
Here I've used C++11's unique_ptr (and consequently also used C++11 syntax for removing copy constructor and assignment operator). Note that on first impression this code seems to have no delete at all; however those deletes are actually hidden in the destructor of unique_ptr. Also note that now the explicit exception handling in the constructor is no longer needed; since the deleting is done in the destructors of the unique_ptrs, C++'s exception handling rules for constructors automatically take care of this.