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 :)
Related
I've found out that unique_ptr can point to an already existing object.
For example, I can do this :
class Foo {
public:
Foo(int nb) : nb_(nb) {}
private:
int nb_;
};
int main() {
Foo f1(2);
Foo* ptr1(&f1);
unique_ptr<Foo> s_ptr1(&f1);
return 0;
}
My question is :
If I create a class with unique_ptr< Bar > as data members (where Bar is a class where the copy constructor was deleted) and a constructor that takes pointers as argument, can I prevent the user from passing an already existing object/variable as an argument (in that constructor) (i.e. force him to use the new keyword) ?
Because if he does, I won't be able to guarantee a valide state of my class objects (the user could still modify data members with their address from outside of the class) .. and I can't copy the content of Bar to another memory area.
Example :
class Bar {
public:
Bar(/* arguments */) { /* data members allocation */ }
Bar(Bar const& b) = delete;
/* Other member functions */
private:
/* data members */
};
class Bar_Ptr {
public:
Bar_Ptr(Bar* ptr) {
if (ptr != nullptr) { ptr_ = unique_ptr<Bar> (ptr); }
} /* The user can still pass the address of an already existing Bar ... */
/* Other member functions */
private:
unique_ptr<Bar> ptr_;
};
You can't prevent programmers from doing stupid things. Both std::unique_ptr and std::shared_ptr contain the option to create an instance with an existing ptr. I've even seen cases where a custom deleter is passed in order to prevent deletion. (Shared ptr is more elegant for those cases)
So if you have a pointer, you have to know the ownership of it. This is why I prefer to use std::unique_ptr, std::shared_ptr and std::weak_ptr for the 'owning' pointers, while the raw pointers represent non-owning pointers. If you propagate this to the location where the object is created, most static analyzers can tell you that you have made a mistake.
Therefore, I would rewrite the class Bar_ptr to something like:
class Bar_ptr {
public:
explicit Bar_ptr(std::unique_ptr<Bar> &&bar)
: ptr(std::move(bar)) {}
// ...
}
With this, the API of your class enforces the ownership transfer and it is up to the caller to provide a valid unique_ptr. In other words, you shouldn't worry about passing a pointer which isn't allocated.
No one prevents the caller from writing:
Bar bar{};
Bar_ptr barPtr{std::unique_ptr<Bar>{&bar}};
Though if you have a decent static analyzer or even just a code review I would expect this code from being rejected.
No you can't. You can't stop people from doing stupid stuff. Declare a templated function that returns a new object based on the templated parameter.
I've seen something similar before.
The trick is that you create a function (let's call it make_unique) that takes the object (not pointer, the object, so maybe with an implicit constructor, it can "take" the class constructor arguments) and this function will create and return the unique_ptr. Something like this:
template <class T> std::unique_ptr<T> make_unique(T b);
By the way, you can recommend people to use this function, but no one will force them doing what you recommend...
You cannot stop people from doing the wrong thing. But you can encourage them to do the right thing. Or at least, if they do the wrong thing, make it more obvious.
For example, with Bar, don't let the constructor take naked pointers. Make it take unique_ptrs, either by value or by &&. That way, you force the caller to create those unique_ptrs. You're just moving them into your member variables.
That way, if the caller does the wrong thing, the error is in the caller's code, not yours.
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.
I'm working on some C++11 examples, but i'm a little rusty. I'm trying to add an object instance to a class attribute. I have something like this:
Entity.h
class Entity {
private:
MyClass object;
public:
Entity();
void doTest();
};
Entity.cpp
#include "Entity.h"
Entity::Entity() {
}
void Entity::doTest(stuff) {
object = new MyClass(stuff);
}
Is this correct? How can i do this in C++?
It's all correct apart from the new. Only use that when you need dynamic allocation; in this case, you just want to create an object:
object = MyClass(stuff);
Or perhaps you want to initialise it in the constructor instead:
Entity(stuff) : object(stuff) {}
It is wrong. object is an object not a pointer. but your code
object = new MyClass(stuff);
treat object as a pointer.
You can either declare object as a pointer in the class Entity or change your function doTest;
If you want a pointer it is better to use smart pointers in C++, such as unique_ptr.
In C++ your object field is really an object. That means that there is an allocated memory inside every Entity object you may create. The problem is how you can initialize that object field ?
if MyClass has no ctor or a ctor callable with no parameter, everything is ok.
if not, you should define the initialization of the field at the same time you define the ctor of Entitythis way
Entity::Entity() : object(parameters) {
code for Entities initialization
}
this is a way to ensure the correctness of your initialization so that object is initialized before you have control on the initialization of the Entity.
Your object is statically initialized inside each Entity, this is a good way, in C++, to code what is called a composition in object oriented programming.
You want to use in the decleration:
MyClass* object
Also, if you are going to use new MyClass make sure you use delete object to avoid leaks.
i.e.
Entity::Entity() { object = NULL; } //constructor
Entity::doTest(stuff) {
delete object;
object = new MyClass(stuff);
}
//Following rule of three, since we need to manage the resources properly
//you should define Copy Constructor, Copy Assignment Operator, and destructor.
Entity::Entity(const Entity& that) { //copy constructor
object = that.object;
//assumes you've correctly implemented an assignment operator overload for MyClass
}
//invoke copy and swap idiom* if you wish, I'm too lazy
Entity& Entity::operator=(const Entity& source) {
MyClass* temp = new MyClass(source.object)
//assumes you've correctly implemented an copy constructor (or default one works) for MyClass.
delete object;
object = temp;
return *this;
}
Entity::~Entity() { //destuctor
delete object;
}
You should avoid dynamic allocation if it is at all possible. You should also use smart pointers (like std::shared_ptr) but if you do wish to use raw pointers, then abide by the rule of three.
*copy and swap idiom
I have code similar to this:
MyClass createInstance()
{
MyClass t;
t.setValue(20);
return t;
}
int main()
{
MyClass primary;
primary.setValue(30);
primary = createInstance();
}
My problem is that createInstance() creates a temporary that is deleted later. In my case, it doesn't use RVO, I have to use The Rule of Three (because my class has a pointer to data members), and I have to do a deep copy of Megabytes of data.
I wonder what's the best way to prevent the creation of a temporary?
Furthermore, I have this MyClass as a member of another class and I would like to prevent the indirection of a pointer and the requirement to manually delete it in the destructor of my parent class.
For example, I could use pointers instead (which would require me to explicitly call the destructor:
MyClass *createInstance()
{
MyClass *t = new MyClass();
t->setValue(20);
return t;
}
int main()
{
MyClass *primary = new MyClass();
primary->setValue(30);
delete primary;
primary = createInstance();
}
Or I could use a member function:
void MyClass::createNewInstance()
{
~MyClass();
init();
setValue(20);
}
int main()
{
MyClass primary;
primary.setValue(30);
primary.createNewInstance();
}
Or I could disallow Assignment/Copying in general:
void MyClass::createInstance()
{
setValue(20);
}
int main()
{
MyClass *primary = new MyClass();
primary->setValue(30);
delete primary;
primary = new MyClass();
primary->createInstance();
}
Am I missing something?
You can't (N)RVO copy into a pre-existing object. The optimization is all about using another freshly created object instead of copying, but in this case the compiler can't guarantee that the assignment object doesn't leave some of the existing state alone (for example).
I would expect that MyClass primary(createInstance()); would enable NRVO for you.
If you really need to assign from a create function your choices are at least two: You can create a temporary and then swap, avoiding the data copy. Alternately with C++11 you could move into the existing object.
Just like what paddy said, how do you know it's not using RVO?
The compiler will do many thing to optimize your code, if it's not in debugging mode.
But, in your creatInstance function, you create a local object, and call a member function on it. The calling of the member function ( t->setValue(20) ) makes it difficult to be optimized, because the compiler will think, the local object is more useful than just an return value. Clearly, we know the local t can be optimized out, but the compiler may not be able to analyze this from its context.
And, by the meaning of "creatInstance", it seems that you just want creat an instance and return it. So, if your constuctor allows to set the value directuly, you can use the RVO:
MyClass creatInstance()
{
return MyClass(20); // if your constuctor makes it possible
}
then, your code will be optimized to this:
// C++ psuedocode
void creatInstance(MyClass* ptr)
{
new (ptr) MyClass(20);
}
int main()
{
MyClass primary;
primary.setValue(30);
// primary = createInstance();
MyClass __temp; // default constructor not called!
creatInstance(&__temp);
primary.operator=(__temp);
// destruct the __temp
}
You may think, it still has to creat temporary object __temp and destroy it , yes, but in your original code, you will creat two temporary object and destroy them, one in your main stack frame, one in your creatInstance function's stack frame.
If you can not sustain the cost of creating temporary object and those stuff, I think you can just change your idea to this:
void modifyInstance(Myclass& objToBeModified)
{
objToBeModified.setValue(20);
// do any change
}
and call it by : modifyInstance ( primary );
by this way, the temporary object creation is definitely prevented!
After all, you just want to change the primary by calling a function, why not writting it directly like above?
For a programming assignment, we are given a template class with two members declared not as pointers, but actual objects:
Foo member;
In the constructor, I tried member = *(new Foo()); initially, but learned that, at least sometimes, it was copying the new Foo object, and therefore causing memory leaks.
I finally discovered member = Foo(), and then looked up what the difference was. I learned that member will be allocated on the stack instead of the heap, and that it will be deleted once it is out of scope. How does this work for objects, though?
Is member only deleted when the parent / class object is deleted?
I also have another question about member = *(new Foo());. I was initializing two member variables of the same type:
// Members
Foo member1;
Foo member2;
// Constructor {
member1 = *(new Foo());
member2 = *(new Foo());
}
For some reason it seemed member1 was not being copied and it retained the same address as the initial Foo (i.e. there was no memory leak when it was deleted). member2 however, would be copied and had a different address, and memory was leaked. Is there an explanation for this?
Your analysis is incorrect. Both of these are memory leaks. What you are doing is allocating a new copy of the object, assigning the value to the member, and then discarding the pointer to the allocated memory without freeing that memory. It is a memory leak in both cases.
Now, consider the following code:
class MemberType {
public:
MemberType() { std::cout << "Default constructor" << std::endl; }
MemberType(int) { std::cout << "Int constructor" << std::endl; }
};
class Example1 {
public:
Example1() {}
private:
MemberType member_;
};
class Example2 {
public:
Example2() : member_(5) {}
private:
MemberType member_;
};
int main(int argc, char** argv) {
Example1 example1;
Example2 example2;
return 0;
}
This code will print both different types of constructors. Note that it did not take any initialization code at all for the member to be initialized in the default manner. Hence your new statement (or even an assignment without new) would be unnecessary in the default initialization case. When initializing members using a constructor other than the default constructor, the proper way to do this is with an initializer list. (The initializer list is what is happening with ": member_(5)" in the example.
Please see the C++ FAQ on constructors for more information about constructing objects in C++.
member = *(new Foo());
new Foo() dynamically allocates a Foo object and returns a pointer to that object. The * dereferences that pointer, giving you the Foo object. This object is then assigned to member, which involves calling the Foo copy assignment operator. By default, this operator assigns the values of each of the members of the right-hand side (the *(new Foo())) object into the left-hand side object (the member).
The problem is this: new Foo() dynamically allocates a Foo object and that object is not destroyed until you delete the pointer returned from the new. You don't save that pointer anywhere, so you've leaked the dynamically allocated object.
This is not the correct way to initialize an object.
member = Foo();
This creates a temporary, initialized Foo object and this object is assigned to member. At the end of this statement (at the ;, effectively), the temporary object is destroyed. member is not destroyed, and the contents of the temporary Foo object were copied into member, so this is exactly what you want to do.
Note that the preferred way to initialize member variables is using the initializer list:
struct C {
Foo member1, member2;
C() : member1(), member2() { }
};