According to definition : When an object of this class is copied, the pointer member is copied, but not the pointed buffer, resulting in two objects pointing to the same so we use copy constructor. But in following class there is no copy constructor but it Works! why? Why i dont need to deep copying?
class Human
{
private:
int* aValue;
public:
Human(int* param)
{
aValue=param;
}
void ShowInfos()
{
cout<<"Human's info:"<<*aValue<<endl;
}
};
void JustAFunction(Human m)
{
m.ShowInfos();
}
int main()
{
int age = 10;
Human aHuman(&age);
aHuman.ShowInfos();
JustAFunction(aHuman);
return 0;
}
output:
Human's info : 10
Human's info : 10
A copy constructor is useful when your class owns resources. In your case, it doesn't - it neither creates nor deletes aValue itself.
If you did do that though, say:
Human()
{
aValue=new int;
}
and properly cleaned up the memory:
~Human()
{
delete aValue;
}
then you'd run into issues, because Human a; and Human b(a); would have the members aValue point to the same location, and the when they go out of scope, the same memory is released, resulting in a double delete.
As has already been mentioned, the reason it works for you is that it's actually fine to have multiple pointers pointing to the same object - that's kind of the point, share data without copying it.
the issues arrive if the object pointed to has it's lifetime managed by the wrapping class, ie: it is created and destroyed within methods implemented by the class - typically the class's constructor and destructor. In that case a deep copy would be necessary in the copy constructor.
In your (admittedly contrived) example where the int has a longer lifetime that the object carrying the pointer you should examine using a reference as a member, initialised in an initialiser list. This removes the possibility of forgetting yourself and deleting the object from within the class.
class Human
{
private:
int& aRef;
public:
Human(int& param)
: aRef(param)
{
}
};
You should also consider whether the pointer or reference should be to a const object:
class Human
{
private:
const int& aRef;
public:
Human(const int& param)
: aRef(param)
{
}
};
This works because the pointer in the class points to the stack variable age.
You haven't written a destructor for your class Human, so doesn't try to do a double delete when the Human is copied in JustAFunction
If you used it differently, for example sending a newed int into the class you would have a memory leak instead.
Human human(new int);
If you copy that, you have two pointers pointing to the same memory, which in itself isn't a problem, but makes it hard to decide who is in charge of releasing that memory.
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'm trying to write a pImpl without using a unique_ptr. I don't understand while writing something like this:
class PublicClass
{
public:
// Some stuff
PublicClass();
private:
class ImplClass;
ImplClass&& mImpl;
};
class PublicClass::ImplClass
{
public:
ImplClass() {}
};
PublicClass::PublicClass() : mImpl(ImplClass()){}
produces following compilation error
Reference member 'mImpl' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object
while writing the following
PublicClass::PublicClass() : mImpl(std::move(ImplClass())){}
is ok. R-value references should not extend life-time of temporaries, as in first snippet?
From class.temporary:
The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:
A temporary bound to a reference member in a constructor's ctor-initializer ([class.base.init]) persists until the constructor exits.
This is applicable to both of your examples. That is, in both of your given cases you have a dangling reference. Its just that in case 2 of your example the compiler is not able to give us the appropriate error/warning.
First of all you must understand that every object requires the storage. You have 3 storages:
Stack
Heap
Static storage (the place where global variables are defined)
Both PublicClass and PublicClass::ImplClass are classes and to create an instance of this class you need the storage.
So you first decide where do you want to allocate the ImplClass.
In case if you want to be able allocate both PublicClass and PublicClass::ImplClass on the stack, compiler must know the size of the ImplClass at compile time. I mean you cannot allocate the object on the stack if the size of the object is not known at compile time at the point where object is created. What you can do is to pre-allocate the memory using char[N] variable
class PublicClass
{
// must be large enough to fit the ImplClass
static constexpr auto PublicClassImplSize = 128;
// The storage for ClassImpl
char alignas(void*) impl_[PublicClassImplSize];
class ImplClass;
public:
PublicClass();
~PublicClass();
};
// cpp
#include <new>
class PublicClass::ImplClass
{
char buf1[10];
// char buf2[10000];
};
PublicClass::PublicClass()
{
static_assert(sizeof(ImplClass) <= PublicClassImplSize);
new (impl_) ImplClass();
}
PublicClass::~PublicClass()
{
reinterpret_cast<ImplClass*>(impl_)->~ImplClass();
}
int main()
{
PublicClass o;
}
In case if you do not care where ImplClass is allocated, you can allocate it on the heap. In this case you use new/delete operators to allocate/release the memory and implement RAII inside the PublicClass to manage the resource.
unique_ptr is an example of the RAII-class. If for any reason you do not want to use it, you must implement the RAII inside the PublicClass. I.e. you implement constructor which allocates the ClassImpl on the heap and you implement the destructor, which releases the resources. You also have to care about move/copy constructors and move/assignment operators, as default behaviour provided by C++ language does not work right here.
class PublicClass
{
class ImplClass;
ImplClass* impl_{nullptr};
public:
PublicClass();
~PublicClass();
PublicClass(PublicClass&&) noexcept;
PublicClass& operator=(PublicClass&&) noexcept;
};
// cpp
#include <new>
#include <memory>
class PublicClass::ImplClass
{
char buf1[10];
// char buf2[10000];
};
PublicClass::PublicClass()
{
auto impl = std::make_unique<ImplClass>();
// ... more initialization
// Initialization is completed
impl_ = impl.release();
}
PublicClass::PublicClass(PublicClass&& obj) noexcept
: impl_(std::exchange(obj.impl_, nullptr))
{
}
PublicClass& PublicClass::operator=(PublicClass&& obj) noexcept
{
delete impl_;
impl_ = std::exchange(obj.impl_, nullptr);
return *this;
}
PublicClass::~PublicClass()
{
delete impl_;
}
int main()
{
PublicClass o;
}
In case if by design you have only one instance of the object, you can allocate the ClassImpl in the global namespace. Personally, I do not like this solution.
Update
I mean you cannot allocate the object on the stack if the size of the object is not known at compile time at the point where object is created
The use of alloca function is out of scope :)
I have a vector of class instances. Each of those instances has a unique_ptr to another class.
Since I never try to copy the class instance or even share the pointer, I felt like unique_ptr are more appropriate than shared_ptrs since the pointer is not shared, but only accessible through the class instance.
Is it bad practice? And why wouldn't this work? I understand that copying an instance to a unique pointer would be ill-formed, but since I move it, I do not understand why this would not be allowed?
Would I have to create a custom move constructor? And what should it do?
The unique ptr should be deleted as soon as the object instance is being removed from the vector as there are no references left, right?
Code Example for better understanding:
class A {
private:
int number;
public:
void f() {
std::cout << "The number is: " << number;
}
A(int i) : number{i} {}
~A() = default;
};
class B {
std::unique_ptr<A> good_a;
B() : good_a{ std::make_unique<A>(1) } {}
~B() = default;
};
int main()
{
std::vector<B> all;
B my_b(123);
all.emplace_back(std::move(my_b));
}
This answer focuses on compilation error you seem to be having. Bad or good practice is left for others to chime in.
Your code have several errors there, but the main one seems to be that your custom B( ) constructor inhibits default move constructor. If you add it, your code becomes well-formed.
Here is a full working code for the reference:
#include <memory>
#include <vector>
class A {
private:
int number;
public:
void f();
A(int i) : number{i} {}
~A() = default;
};
struct B {
std::unique_ptr<A> good_a;
B(int k) : good_a{ std::make_unique<A>(k) } {}
B(B&& ) = default;
B& operator=(B&& ) = default; // not needed for the example, but good for completeness
};
int main()
{
std::vector<B> all;
B my_b(123);
all.emplace_back(std::move(my_b));
}
And why wouldn't this work?
What you described could work.
I do not understand why this would not be allowed?
What you described would be allowed.
Would I have to create a custom move constructor?
No, that wouldn't be necessary, unless you define other special member functions, or have other members (beside the unique pointer) that have deleted or private move constructor.
The unique ptr should be deleted as soon as the object instance is being removed from the vector as there are no references left, right?
Members are destroyed when the super object is destroyed. And the destructor of the unique pointer invokes the deleter on its owned pointer.
Whether there are references to the pointed object has no effect on whether it is deleted or not. Anything referring to the deleted object will be left dangling.
Is it bad practice?
There isn't necessarily anything particularly bad about what you described in general, but that depends on exact details.
One potential issue is that dynamic allocation can be expensive in some cases, and using it unnecessarily would then be unnecessarily expensive. As such, you should to have some reason to allocate the pointed objects dynamically rather than storing them directly as members.
Bugs in your example:
You attempt to initialise B(123) but B has no constructor accepting an integer.
You attempt to initialise a B outside a member function of B, but its constructors and the destructor have private access.
You have user declared destructor for B, but no user declared move constructor or assignment operators and therefore the class isn't movable, which is a requirement for storing in std::vector.
Here is a fixed version that doesn't use unnecessary dynamic allocation:
struct A {
int number;
};
struct B {
A good_a;
};
B my_b{123};
all.push_back(my_b);
Please read this answear.
Depending what is explicitly declared respective constructors with default implementation are implicitly defined or dropped. Rules are described by this table:
Since you have used explicit defined destructor (as default) you have disabled ("not declared") move constructor.
So to fix it you have to explicitly define move constructor or remove definition of destructor: https://godbolt.org/z/dr8KrsTfq
I am using a boost::ptr_vector, but I believe this applies to a standard std::vector as well. I am trying to place pointers to objects polymophically into a boost::ptr_vector the hierarchy is that I have an Entity that inherits from Object being created with the line
Object * newObject = new Entity(param1, param2); // then I attempt to add it to the ptr_vector
but if I break the program (Visual Studio 2010) to look at what is being held the pointer is never redirected from garbage, and garbage is being held. I step through the code, and it does enter the parameterized constructor, and follows the correct logical steps with it.
I am uncertain what is going wrong. do I need to have specific member functions in the parent, or the child in order for this polymorphic behavior to work (currently all children have parameterized constructors unique to their type, and destructors along with polymorphic interaction methods). must I have assignment operators, or should I have a constructor in the Object class.
It seems to be that the call to operator new is not resolving to an object, but resolving to something else, but VS2010 is not throwing an error.
Edit: explanation of what should be happening.
stepping through a 2D std::vector(rectangular/non-jagged)
using case/switch to determine object to be generated, and added to structure
pointer to Object is created, and assigned to new // I think this is where the problem is happening
then the reference of that pointer is pushed onto a manager-member boost::ptr_vector
in Visual Studio 2010 I put a break at the line to create the pointer, and assign new (polymorphic), and one on the line for the push_back() to the boost::ptr_vector watching the pointer. The temp pointer value is created, and stepping into the constructor it follows all logical steps for that constructor, and when the constructor finishes, and the stack returns to the line that called the constructor the pointer is still the same value (I think this is acceptable), but when I look at the object that it points to all the values show up as question marks (including the statically composed member objects). then when the push back triggers, and enters boost-header the x value show the same information.
it almost seems like the pointer is being made, and the datams of the object are created, but once the constructor is finished it doesn't actually assign the values to the parent class object which should be considerably simple with regards to polymophic behavior.
example headers of concern (the real headers do have member variables, and their implementations are in a separate cpp file):
class Object{
public :
virtual void interact(int action, Object& source){}
virtual void updateObject(float duration){}
virtual ~Object(){}
bool operator==(const Object& _other)const;
bool operator!=(const Object& _other)const;
};
class Entity : public Object{
public:
Entity(Vector3 location, Type thisType, SpecialType difficulty=noSpecial);
~Entity();
void interact(int action, Object& source);
void updateObject(float duration);
};
Edit: changing context to better target problem at hand, and receive a solution
The pointer value only changes after the constructor has finished, it's not a problem. It's logical because first a temporary pointer is acted upon and only the it is assigned to your pointer.
After
Object * newObject = new Entity(param1, param2);
you will have newObject pointing to the freshly created object. While the constructor is
running, newObject is still not assigned. If you have afterwards e.g.
vec.push_back(newObject);
you can step into the push_back method and see the argument is an Object having
a virtual table referencing to Entity methods. (You have a virtual destructor at least,
right?)
Based on what you've posted, it's difficult (if even possible) to be sure of the problem, not to mention how it's coming about/how to fix it.
Perhaps it's better to start from something that actually works, and add the functionality you need, or at least get some idea of places you're deviating from what's expected/what works. So, here's a small sample of creating objects dynamically, putting them into a ptr_vector, using a virtual function in each to verify that what's in the container is what's expected, and then letting the container go out of scope (and in the process, destroying the objects referred to by the pointers it contains).
#include "boost/ptr_container/ptr_vector.hpp"
#include <iostream>
#include <string>
#include <sstream>
class Object {
std::string name;
public:
Object(std::string const &n) : name(n) {}
virtual std::ostream &write(std::ostream &os) const {
return os << name;
}
virtual ~Object() { std::cout << "Object being destroyed\n"; }
};
class Entity : public Object {
int value;
public:
Entity(int v, std::string name) : Object(name), value(v) {}
std::ostream &write(std::ostream &os) const {
return os << "Entity: " << value;
}
~Entity() { std::cout << "Entity being destroyed\n"; }
};
int main() {
boost::ptr_vector<Object> objects;
for (int i=0; i<10; i++) {
std::stringstream name;
name << "object: " << i;
if (i & 1)
objects.push_back(new Object(name.str()));
else
objects.push_back(new Entity(i, name.str()));
}
boost::ptr_vector<Object>::iterator pos;
for (pos = objects.begin(); pos != objects.end(); pos++) {
pos->write(std::cout);
std::cout << "\n";
}
return 0;
}
At least for me, the output looks like this:
Entity: 0
object: 1
Entity: 2
object: 3
Entity: 4
object: 5
Entity: 6
object: 7
Entity: 8
object: 9
Entity being destroyed
Object being destroyed
Object being destroyed
Entity being destroyed
Object being destroyed
Object being destroyed
Entity being destroyed
Object being destroyed
Object being destroyed
Entity being destroyed
Object being destroyed
Object being destroyed
Entity being destroyed
Object being destroyed
Object being destroyed
For what it's worth, note the destructors -- when an Object is destroyed, only the base dtor is invoked, but when an Entity is destroyed, first the derived dtor is invoked, then the base dtor is invoked (so we see both 'Entity being destroyed' and 'Object being destroyed").
What would make a field variable become obsolete before entering the destructor upon deletion of the object?
I was a looking for an answer for this problem I'm having on this site and came across this:
Lifetime of object is over before destructor is called?
Something doesn't add up at all: if I've declared a pointer to SomeClass inside another WrapperClass, when I construct the WrapperClass I need to create a new SomeClass and delete it on destruction of the wrapper.
That makes sense and has worked so far.
The pointer is still valid and correct well into the destructor otherwise obviously I wouldn't be able to delete it.
Now my problem is that my field members (both an int and a pointer to a SomeClass array) of WrapperClass are garbage when I call the destructor. I've checked the wrapper object just after construction and the data is fine. The wrapper is actually a pointer in another Main class and the problem occurs when I destruct that Main (which destructs the wrapper) but works fine if I just delete the wrapper from another method in Main.
My paranoia led me to the above mentioned answer and now I'm totally confused.
Anybody care to shed some light on what's really going on here?
EDIT:
Node is the SomeClass.
class WrapperException{};
class Wrapper {
private:
struct Node { /*....*/ };
int numNodes;
Node** nodes;
public:
Wrapper() : numNodes(0) { nodes = new Node*[SIZE]; }
Wrapper(const Wrapper& other) { throw WrapperException(); }
Wrapper& operator=(const Wrapper& other) { throw WrapperException(); }
~Wrapper() { //calling delete Main gets me here with garbage for numNodes and nodes
for(int i = 0; i < numNodes; i++)
delete nodes[i];
delete nodes;
}
};
class MainException{};
class Main {
public:
Main() { wrapper = new Wrapper(); }
Main(const Main& other) { throw MainException(); }
Main& operator=(const Main& other) { throw MainException(); }
~Main() { delete wrapper; }
private:
Wrapper* wrapper;
};
You need to use the Standard library to implement this behaviour.
class Wrapper {
private:
struct Node { /*....*/ };
int numNodes;
std::vector<std::unique_ptr<Node>> nodes;
public:
Wrapper() : numNodes(0) { nodes.resize(SIZE); }
// No explicit destructor required
// Correct copy semantics also implemented automatically
};
class Main {
public:
Main() : wrapper(new Wrapper()) {}
// Again, no explicit destructor required
// Copying banned for move-only class, so compiler tells you
// if you try to copy it when you can't.
private:
std::unique_ptr<Wrapper> wrapper;
};
This code is guaranteed to execute correctly. When in C++, if you have used new[], delete or delete[], then immediately refactor your code to remove them, and review three times any use of non-placement new- constructing a unique_ptr is pretty much the only valid case. This is nothing but a common, expected outcome of manual memory management.
Since Grizzly isn't answering, I'll put this out there.
Both your Main class and your Wrapper class need properly implemented copy constructors and assignment operators. See The Rule of 3.
The problem is, if your class ever gets copied(which is easy to happen without you even realizing it), then the pointers get copied. Now you've got two objects pointing to the same place. When one of them goes out of scope, it's destructor gets called, which calls delete on that pointer, and the pointed to object gets destroyed. Then the other object is left with a dangling pointer. When it gets destroyed, it tries to call delete again on that pointer.
The lifetime of your wrapper object has ended, but the integer and pointer sub-objects as well as the pointee are still alive. When you invoke delete on the pointer, the pointee's lifetime ends, but the pointer still remains alive. The pointer's lifetime ends after your dtor is complete.
Thus, if your members have become corrupted, there is something else afoot.
Node** nodes;
should be
Node * nodes;
Also the destructor is wrong. It should be:
for(int i = 0; i < numNodes; i++)
delete nodes[i];
delete [] nodes;
There might be other problems as well as e.g. you haven't created a copy constructor or assignment operator so that might make it so that the copy of an object then deletes the object for you.
EDIT: changed the destructor...