Stack and heap allocations of instantiated objects C++ - c++

I've got a background in C and am trying to get my head around C++ classes and how the destructors get called as objects leave scope. As a side note, given the nature of what I am trying to do, I would rather not use STL structures like std::array<> or std::vector<> for the data containers I present below.
Here's a high level overview of my understanding. Given some class:
class some_class{
public:
int * member;
size_t n_members;
some_class(size_t count) ...
~some_class() ...
// a member function or operator overload
// that returns an instance of some_class
some_class do_something()
}
...
some_class * container;
// Some scope
{
some_class foo = some_class();
some_class * bar = new some_class();
container[0] = bar;
}
When some_class foo leaves the scope, its destructor gets called. If I wanted to store a pointer to an instance of some_class into container outside of the scope, I need to instantiate some_class bar on the heap so that memory does not immediately get de-allocated upon leaving scope - just like I would in C.
Now, the purpose of some_class is to hold an arbitrarily large amount of data and so int * member needs to be allocated on the heap.
Given above, the constructor and destructor for some_class() will look something like this:
// some_class constructor
some_class::some_class(size_t count) : n_members(count){
member = new int[count];
}
// some_class destructor
some_class::~some_class(){
delete[] member;
}
Now my problem becomes apparent: If I need to add an instance of some_class returned from the do_something() method, I am guaranteed to have a memory error (in this case, a double-free) because do_something() returns a stack-allocated some_class:
some_class * container = new some_class[n];
// Some scope
{
some_class foo = some_class();
some_class bar = foo.do_something();
container[0] = &bar; // <-- I know this is stupid but that's the point of this question
}
delete[] container;
My way around this is to make foo.do_something() return a pointer to an instance of some_class. Of course, not a solution. How would one properly address such a situation in true C++ way?
For example, one thing I've been reading up on was the use of shared pointers or unique pointers (or smart pointers in general). However, my understanding is that using these pointers requires you to have instantiated your object in the heap. It also really doesn't help the whole issue about requiring foo.do_something() to return a pointer.
Anyways, any thoughts would be appreciated.

Smart pointer can be used to hold pointer inside some_class like this:
#include <memory>
class some_class{
public:
// smart pointer instead of raw pointer
std::unique_ptr<int[]> member;
size_t n_members;
some_class(size_t count = 0) : member(new int[count]), n_members(count) {}
// destructor not needed
// a member function or operator overload
// that returns an instance of some_class
some_class do_something();
};
int main()
{
int n = 3;
// smart pointer instead of raw pointer
std::unique_ptr<some_class[]> container(new some_class[n]);
{
some_class foo = some_class(10);
some_class bar = foo.do_something();
// use std::move to transfer pointer ownership
container[0] = std::move(bar);
}
// no need to delete
}

I used to be proficient in C++, but moved to Java long ago and my C++ is rusty now :(.
One thing you can do is create a constructor that accepts a member of the class. Inside it, just copy the properties to your new instance. (Also it is possible to make it with a static method instead of overloading the constructor).
some_class::some_class(some_class* obj){
member = obj->member;
n_members = obj->n_members;
}
So you can do this in your code:
some_class * container;
// Some scope
{
some_class foo = some_class();
some_class * bar = new some_class();
container = new some_class(bar);
}
Hope it works for you.

Related

Should I delete pointer from `new` passed to a function which makes into a `shared_ptr`?

In the following code example:
#include <iostream>
class Foo{
};
class Bar{
public:
void addFoo(Foo *foo){
auto my_foo = std::shared_ptr<Foo>(foo);
}
};
int main() {
auto bar = Bar();
bar.addFoo(new Foo());
return 0;
}
Do I need to clean up the pointer created in main() by the bar.addFoo(new Foo) call, or will this be taken care of by Bar which creates a shared_ptr of it? My understanding is that auto my_foo = std::shared_ptr<Foo>(foo); will use the copy constructer to copy this pointer into my_foo leaving the original one dangling, is that correct?
The very idea of a constructor taking a raw pointer is to pass the ownership to std::shared_ptr. So, no, you don't have to delete a raw pointer passed to std::shared_ptr. Doing this will lead to a double deletions, which is UB.
Note that in general passing a raw pointer is dangerous. Consider the following more generalized example:
void addFoo(Foo *foo){
// some code which could throw an exception
auto my_foo = std::shared_ptr<Foo>(foo);
}
If an exception is throw before my_foo is constructed, foo will leak.
If you have no special reason to pass a raw pointer, consider the following alternative:
class Bar {
public:
template<class... Args>
void addFoo(Args... args){
auto my_foo = std::make_shared<Foo>(args...);
}
};
int main() {
auto bar = Bar();
bar.addFoo();
return 0;
}
Here you pass arguments (if you have any) to construct Foo inside addFoo() instead of constructing Foo before invoking addFoo().
Perfect forwarding of args... could be used if it is needed:
template<class... Args>
void addFoo(Args&&... args){
auto my_foo = std::make_shared<Foo>(std::forward<Args>(args)...);
}
The code you wrote is correct. But in modern C++, you should not be using raw pointers, new and delete unless you have to interoperate with code that does. If you can help it (and if question comments are any indication, you can), use smart pointers all the way through:
#include <iostream>
#include <memory>
class Foo {};
class Bar {
public:
void addFoo(std::unique_ptr<Foo> foo) {
auto my_foo = std::shared_ptr<Foo>(std::move(foo));
}
};
int main() {
auto bar = Bar();
bar.addFoo(std::make_unique<Foo>());
return 0;
}
Above, the addFoo member function receives the pointer as a unique_ptr, and uses std::move to transfer ownership of the pointer from the unique_ptr to the shared_ptr without copying the referent; after constructing the shared_ptr, the unique_ptr is left in an empty state. You could also have addFoo receive a shared_ptr directly, or construct the object in-place inside the member function, as in Evg’s answer.
Using unique_ptr instead of a raw pointer makes it clear that the method intends to take ownership of the allocation, and encourages callers to use smart pointers themselves, making it less likely they will forget to delete their allocations later.
A raw pointer does not manage end of life, but a shared pointer does. When you create a shared pointer from a raw pointer, the shared pointer takes ownership of the object. That means that the object will be destroyed when the last shared pointer pointing to it will go out of scope.
In your code, my_foo takes ownership of the object created with new Foo(), goes out of scope when addFoo returns, and as it contains the only shared reference, correctly destroys the object.
The correct, c++ way to do this, would be the following:
#include <iostream>
class Foo{
};
class Bar{
public:
void addFoo(Foo foo){
auto my_foo = std::make_shared<Foo>(foo);
}
};
int main() {
auto bar = Bar();
bar.addFoo(Foo());
return 0;
}
This avoids any raw pointers or naked new, and is totally exception safe. Also, std::make_shared introduces some performance benefits.
One confusing thing here is that the code seems to be unnecessarily copy the Foo object, however, since C++17, due to Return Value Optimization, (RVO), you are guaranteed to have no copies at all (when passing Foo as an argument to addFoo).
You can create the shared pointer with make_shared. If you want to construct Foo in main (e.g. because you have the paramters available there), then use make_shared at the point of construction and pass the shared_ptr on.
#include <iostream>
class Foo{
~Foo() { std::cout << "Foo destructed" << std::endl; }
};
class Bar{
public:
void addFoo(std::shared_ptr<Foo> foo){
auto my_foo = foo;
}
};
int main() {
auto bar = Bar();
bar.addFoo(std::make_shared<Foo>());
return 0;
}
delete also calls your destructor. You can test, whether the shared pointer destructs your object or whether a delete is needed by printing out a message.

error: 'new' cannot appear in a constant-expression

class A
{
int data;
public:
void display()
{
cout<<"Value is "<<data;
}
void set_data(int x)
{
this->data = x;
}
A object = new A();
};
When I run the above code, I get the error stating "new cannot appear in constant expression". Why is it so?
Operator new returns a pointer but A is not a pointer type. You want A*:
A* object = new A();
You also want to move the above statement outside your class body and place it into appropriate function such as main():
int main() {
A* p = new A();
// do work
delete p;
}
That being said you either don't need a pointer at all and you can simply use an object with automatic storage duration:
A object;
Or you want to consider using a smart pointer such as std::unique_ptr:
std::unique_ptr<A> p = std::make_unique<A>();
class A
{
public:
A * object = new A(); // In any case not: "A object = new A();"
};
Or:
class A
{
public:
A object;
};
-
See (let's assume, for a moment, that you don't get the error), in both cases, on the first construction of A object, it creates another A object as a data-member. This A data-member (let's call it object.object ) creates in its turn another A as its data-member (let's call it object.object.object), and so to infinity (or until no more memory). I mean, as a data-member, it can't be either as A* object = new A();, or as A object;
-
I am not sure what was your intention, but if you want to link one A-object to another A-object, the class should be something like that:
class A
{
public:
A * object = nullptr
};
you have to make object of class A into main().
void main(){
A object;
}
First of all, you cannot create an object in the class declaration. Class declaration is like a blue print of the class. It is to say these are the components of my class - variables and member functions. You cannot instantiate anything inside it as no memory is allocated during this stage.
Note that you can instantiate an object inside one of the member function including constructor. These are called during object creation when memory is allocated.
Even if you use this statement inside a constructor you will go into an infinite loop as the constructor calls its constructor and so on until you have memory overflow.
You can declare the object in main like this:
int main() {
A obj = new A();
//other operations
} //Object A is destroyed once you come out of main.
Or dynamically like this
int main() {
A* obj = new A(); //dynamic allocation
//other operations
delete obj; //explicitly destroy
}

C++ force dynamic allocation with unique_ptr?

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.

delete nested class objects correctly?

My code is like following, basically I am using some external library and embed some class objects from this library to myClass, then do things with OBJ,
#include "extern_lib.h" //some library
class myClass
{
public:
extern_class *obj1;
extern_class *obj2;
double arr[3];
};
int main()
{
myClass *OBJ= new myClass();
OBJ->obj1 = new extern_class(arg1...);
OBJ->obj2 = new extern_class(arg2...);
//do something like
OBJ->obj1->extern_fun1(arg1...);
OBJ->obj2->extern_fun2(arg2...);
//delete
delete OBJ;
return 0;
}
I would like to know,
1- in order to free all the objects, is it enough to delete OBJ?
2- is there better ways to write this code?
No, it is not enough. You have to call delete for every new you place in your code explicitely.
Use smart pointers like std::unique_ptr or better, use RAII. To clarify that: smart pointers and RAII are not even only better ways of doing so, they are the ways of doing it correctly in modern C++.
Here's an adequate example with RAII:
#include "extern_lib.h"
class myClass
{
public: // note that public members are possibly bad design (depending on your situation)
extern_class obj1;
extern_class obj2;
double arr[3];
};
int main()
{
myClass foo;
foo.obj1.extern_fun(arg1...);
foo.obj2.extern_fun(arg2...);
return 0;
}
Please note that it's not possible to use RAII in every situation. If you run into such, use smart pointers as stated:
#include "extern_lib.h"
class myClass
{
public: // note that public members are possibly bad design (depending on your situation)
std::unique_ptr<extern_class> obj1;
std::unique_ptr<extern_class> obj2;
double arr[3];
};
int main()
{
myClass foo;
foo.obj1 = std::unique_ptr<extern_class>(new extern_class(arg1...));
foo.obj2 = std::unique_ptr<extern_class>(new extern_class(arg2...));
foo.obj1->extern_fun(arg1...);
foo.obj2->extern_fun(arg2...);
return 0;
}
In order to free all the objects, is it enough to delete OBJ?
No, this will produce a resource leak as the (default) destructor of myClass doesn't care about deleting the pointer members.
Is there better ways to write this code?
Yes, use smart pointers. For example:
class myClass
{
public:
std::unique_ptr<extern_class> obj1;
std::unique_ptr<extern_class> obj2;
double arr[3];
};
In general, try to make resources owned by classes. That is, allocate them in the constructor and deallocate them in the destructor. The standard library's smart pointers will already do that job for you. Avoid managing more than one resource inside a single class.
By the way: If your example is not contrived and you are really not using polymorphism at all, then just get rid of all those news and simply use variables with automatic storage duration. C++ is not Java.
Update: Here is (one way of) how to get rid of new if polymorphism is not needed:
class myClass
{
public:
extern_class obj1;
extern_class obj2;
double arr[3];
myClass(type arg1a, ..., type arg2a, ...) : obj1(arg1a, ...), obj2(arg2a, ...)
// ^^^^ member initializer list ^^^^
{
}
};
The key is to create the member objects as part of the process of creating myClass by using a so-called member initializer list. If you are programming C++11, prefer writing obj1 {arg1a, ...}, obj2 {arg2a, ...} for consistency. (The old syntax still works equally well, however.)
Likewise in your main function:
int
main()
{
myClass mc(arg1a, ..., arg2a, ...); // (1)
mc.obj1.extern_func(...);
mc.obj2.extern_func(...);
return 0; // (2)
}
At line (1), we create an instance of myClass on the stack using our new constructor that will create the members obj1 and obj2 correctly. The compiler-generated default constructor of myClass will correctly destruct mc.obj1 and mc.obj2 as mc goes out of scope on line (2). Again, in C++11 line (1) can be written more cleanly as myClass mc {arg1a, ..., arg2a, ...};.

C++ private constant pointer

I am learning pointers in c++ and am having some trouble.
I have a class Foo that in the header file declares some data:
private:
const Bar *obj;
Where Bar is a class.
Then in the c++ implementation I want to replace *obj so that it points to a completely different Bar object. *obj is constant, so how do I change what is in what *obj points to or rather, what is in memory at *obj? Also in Foo's destructor, how do I deallocate *obj?
Given your class definition
class A {
private:
const Bar *obj;
};
obj is a pointer to a constant Bar object. You can change what that pointer points to, but you cannot change the contents of the object pointed to.
So, if you have a new Bar object and you'd like to change obj so it points to that, you can simply assign the new value:
/* New object: */
Bar *new_bar = new Bar;
/* Change the pointer: */
obj = new_bar;
There are two issues, however.
If the new Bar object is created outside the class, you cannot directly assign it to obj because the latter is private. Hence you need a setter function:
class A {
private:
const Bar *obj;
public:
void set_obj(const Bar *new_obj) { obj = new_obj; }
};
You must determine who will eventually own the Bar object, i.e. who is responsible for freeing the heap space it takes. If the caller is responsible then you can code it as above, i.e. class A will never create new Bar objects, nor delete any. It will just maintain a pointer to Bar objects created and deleted outside the class.
But if class A above is actually responsible for the memory space taken by the Bar objects, you must use delete obj in the destructor to free the space, and you must also free the space when you get a new Bar object assigned. That is, the set_obj function above needs to be changed to this:
void set_obj(const Bar *new_obj) { delete obj; obj = new_obj; }
Otherwise you'll have a memory leak. Similar measures must be taken in the copy constructor (unless you delete it), as well as the assignment operator: Both functions are used whenever a copy of a class A object is made, and in that case you must make sure that you do not simply copy the pointer, but instead allocate fresh space and copy the object (i.e. you must perform a deep copy):
A(const A& a):obj(new Bar(*a.obj)) {}
A& operator=(const A& a) { delete obj; obj = new Bar(*a.obj); return *this; }
Having said this, if your class is responsible for the memory space, it is a much better idea to use a smart pointer class instead of a raw pointer. The main reasons are: (i) The above is quite complicated and it's easy to make mistakes; (ii) The above is still not very good – there may still be memory leaks or worse problems when an exception is thrown, e.g. in the constructor of Bar. C++11 provides a smart pointer class called std::unique_ptr, which seems ideal for your purposes:
class A {
private:
std::unique_ptr<const Bar> obj;
public:
~A() {}
void set_obj(std::unique_ptr<const Bar> new_obj) { obj = new_obj; }
};
With this in place, the smart pointer will take care of any memory space that needs to be freed automatically, both at destruction time as well as when a new Bar object is assigned to the pointer.
You cannot use that pointer to to change the value that's being pointed to, that's why it's a const, but you should be able to change what it is pointing to.
On c++ "const Bar *obj;" means that you have a pointer to a readonly Bar object; meaning that you can point it to any readonly Bar object.
You can also point a non constant variable, thus promising that you will not change it using that pointer.
If you want to have a pointer, that is constant in the sense that it can't be made to point anything else, then you should write it this way:
Bar * const obj = some_object;
This will compile and work fine:
const int p = 1, q = 2;
int r = 3;
const int* i = &p;
i = &q; // point it to a different const variable.
i = &r; // point it to a different non const variable.
As written I believe that this is a pointer to a const Bar object and not a constant pointer.