by intermittence reference I mean the following
shared_ptr<int> a = new int(100);
int* i = a;
shared_ptr<int> b = i;
would the reference count of b be two?
also if it is aware, would still be valid in the following code?
//
shared_ptr<int> a = new int(100);
{// workspace
int* i = a;
shared_ptr<int> b = i;
}// end of workspace
If no to above question, how could I achieve it?
I would to make my memory allocation safe by using smart pointer. I have a data structure tree that would create new tree nodes (pointers to allocated memory) that is either inserted into tree or passed out.
If it is within the tree, no problem, I can control the life cycle. If it is passed out, then I have no control.
The version you wrote in your example will not compile. But to answer the spirit of what I think your question is here is an example
#include <memory>
int main() {
std::shared_ptr<int> a = std::make_shared<int>(100);
int* i = a.get();
std::shared_ptr<int> b(i);
}
This does not have a and b related as far as reference counting. Instead they both (mistakenly) take ownership of the same underlying pointer, pointed at by i and will result in a double free or corruption when a falls out of scope since they both try to delete it.
The correct way for both shared_ptr to reference the same underlying pointer and have correct reference counting behavior is simply
#include <memory>
int main() {
std::shared_ptr<int> a = std::make_shared<int>(100);
std::shared_ptr<int> b = a;
}
Related
I want to create a class that contains a pointer, and upon initialization, the pointer can be dereferenced to give an integer assigned at initialisation.
This was my first attempt to write this code. This passed compiler and gave me the correct result without warning. However I later think this code has a potential problem.
That is in the constructor, the integer a is created on a stack framed to the constructor function. I am however making 'ptr' pointing to this stack memory address. The problem is this memory can be reused upon maybe calling other functions, so I might get garbage value if I am not lucky.
#include <iostream>
using namespace std;
class P {
public:
int *ptr;
P(int);
};
P::P(int a){
int *ptr = new int (0);
ptr = &a;
}
int main() {
P p(99);
cout <<*(p.ptr) <<endl;
}
A better way would be to create an integer variable on heap, copy the value of a to that variable, and make ptr pointing to that memory space on heap.
P::P(int a){
int *i = new int (0);
*i = a;
ptr = i;
}
Is my analysis correct?
Thanks!
The statements
int *ptr = new int (0);
ptr = &a;
are problematic, but probably not because of the reasons you think.
The reason it's problematic is because you define a new and distinct local variable ptr inside the function. This is not the same as the P::ptr member variable.
There's also a second problem, which is a memory leak. You allocate memory with new, but you never free the memory with delete.
If you really is required to use a raw and non-owning pointer to a single int value, I recommend you do it using a constructor initializer list:
P(int a)
: ptr{ new int(a) }
{
// Empty
}
Here new int(a) will create a new int value and copy the value of a into it.
Remember to then create a destructor which free's the memory you have allocated. And then you need to learn about the rules of three, five and zero.
To use the rule of zero, and to avoid memory leaks and make life simpler, use a smart pointer like std::unique_ptr:
struct P
{
std::unique_ptr<int> ptr;
P(int a)
: ptr{ std::make_unique<int>(a) }
{
}
};
And of course, since it's just about a single int value, and you don't need a reference to the original value, there's no need for pointers at all.
I have the following simple code, and I have not found a thread where smart pointers are used for this simple case, but rather copy objects:
int main()
{
int i = 1;
std::unique_ptr<int> p1(&i);
*p1 = 2;
return 0;
}
This results in _BLOCK_TYPE_IS_INVALID when the pointer goes out of scope. If I call p1.release(), the code works fine and I do not get this error. I thought such pointers are smart enough to handle dangling pointers?
An alternative would be if I had a copy of i, which does not give the above error:
std::unique_ptr<int> p1(new int(i));
What is the advantage of using smart pointers here, where I do not want to perform the local copy?
If I were to use a raw pointer:
int i = 1;
int *p1 = &i;
*p1 = 2;
I would not get an error, even if I don't code:
p1 = nullptr;
std::unique_ptrs are for handling dynamically allocated memory; they're said to take ownership of the pointer when you construct one.
Your int i; is on the stack, and thus isn't dynamically allocated; it's ownership can't be taken away from the stack. When the unique_ptr destructor tries to delete the pointer you gave it (because it thinks nobody owns it anymore), you get that error because delete can only be used for pointers created with new.
Given your short example, I don't know what context this is in... But you should use raw pointers (or make a copy, as you said) for stack-allocated variables.
The answer provided by #qzx is the main reason of the problem you've reported in your code
One additional thing about std::unique_ptr<> usage. You should always try to use std::make_unique<>() to create a std::unique_ptr. It sometimes help in using this pointer appropriately by providing appropriate compilation errors.
For example, if you change the above code with std::make_unique<> as
int i = 1;
std::unique_ptr<int> p1 = make_unique<int>(&i);
then most compiler will give error as
can't convert int* to int
It will help you to use a copy which creates a totally new integer whose ownership is taken by std::unique_ptr<>
int i = 1;
std::unique_ptr<int> p1 = make_unique<int>(i);
*p1 = 2;
This code works.
I have this code which works perfectly :
int* a;
int* b;
*a = 10;
*b = 5;
int *c;
int t;
t=*a+*b;
c = &t;
At the end, c points to t which is equal to 15.
Now, I want to do the exact same thing with an abstact class myObject.
I have :
myObject* a;
myObject* b;
*a = myObject();
*b = myObject2();
myObject *c;
myObject t; // Of course, this fails since myObject is an abstract class
t=*a+*b;
c = &t;
To avoid creating a buffer variable, and to be able to get a pointer to the result of my addition, I've done this :
myObject* a;
myObject* b;
*a = myObject();
*b = myObject();
myObject* c;
c = &(*a+*b);
This code works exactly as I wanted to but I'm afraid this code is not legit. I fear that the memory pointed by *c could be erased at any moment. Is this the good way to do this ?
I'm sorry If this question have already been posted, I've been searching for hours without getting an answer.
EDIT 1 : It seems that I did not correctly explained my problem :
Let's say that myObject can be an int, a double or a float.
I don't know which of these I have when creating a and b, this is why I have a pointer of type *myObject .
I have defined every possible combination between adding an int with an int, an int with a double ...
Thanks to this, I can now add two myObject even when ignoring the real type pointed by my pointer *myObject.
The problem know is that I want to get a pointer to the result of my operator+ with gives back a myObject&.
I hope this is a little more clear.
Thanks
The behaviour of code of the form
int* a; *a = 10;
etc. is undefined: a does not point to memory that you own, so you can't dereference it. Your code may well "work perfectly", but in reality the compiler reserves the right to eat your cat.
In C++, you tend to use new to construct an object if it's not feasible to use automatic or static storage. The result of new is a pointer of the created type. You should store that for a subsequent delete. Consider writing
A* a = new A();
/*some code*/
delete a;
assuming A has a default constructor, or more simply
A a;
or even the more flashy
A a{};
if automatic storage duration is sufficient.
Thou shall never dereference uninitialized pointers, it invokes undefined behaviour which is evil.
You must absolutely make you pointers reference true variables before using them. You can use new as explained by #Bathsheba (but do not forget to delete then), or simply use the address of an existing variable:
int var_a;
int *a = &var_a;
...
It is the same when using objects:
A* a;
A* b;
a = new myObject(); // don't forget to delete the new allocated pointers
b = new myObject2();
And then:
A c = (*a + *b); // do define a true object
That last part is another problem: *a + *b creates a temporary object which will be destroyed at the end of the full expression (when semi colon ; is reached). If you affect its address to a pointer, you will end with a dangling pointer, meaning it points to a deallocated memory that can be overwritten at any moment => again invoking Undefined Behaviour
Eg I'm pretty sure this works.
int foo = 51;
int* bar = &foo;
foo = 3;
So bar is still valid, and *bar == 3.
What about if we say
std::unique_ptr<int> foo(new int(51)); // should probably use make_unique
int* bar = foo.get();
foo.reset(new int(3));
Am I guaranteed that *bar == 3?
Or am I causing undefined behavior by continuing to reference bar?
No, not at all. You will get undefined behaviour, as the raw pointer managed by the unique_ptr is changed by the reset. In fact, the unique_ptr deletes the managed pointer and reallocates a new one, so your old pointer will keep pointing to the old address, which is no longer valid. Your code is equivalent to this:
#include <iostream>
int main()
{
int* managed = new int(51); // equivalent to unique_ptr(new int(51));
int* bar = managed; // equivalent of unique_ptr::get
delete managed; managed = new int(3); // equivalent to unique_ptr::reset(new int(3))
std::cout << *bar << std::endl; // Wrong!!! Undefined behaviour, bar is dangling!
}
Your first code snippet is indeed correct, since you are not changing any address there, you are just changing the variable the pointer points to, so of course dereferencing the pointer will get you the updated value.
No, if you reset a unique_ptr, it will delete the pointer it owns.
You can do:
int* bar = foo.release();
This causes foo to give up ownership of its pointer and return it.
No, std::unique_ptr.reset will delete the existing pointer.
See http://www.cplusplus.com/reference/memory/unique_ptr/reset/
For your purpuse use release.
Consider I have the function:
int &create_ptr(){
int *x = new int;
*x =5;
return *x;
}
int main(){
int y = create_ptr();
}
Will this cause a memory leak or is there somehow to delete it?
Sorry if it's a basic question, this has just been bugging me and I couldn't really find the answer.
Thank you everyone, makes sense now!
To satisfy your curiosity, yes you can delete it safely, but only if you return it by reference (pointer or C++ reference (&)). By reference so as to retain the original address of your newed object. You need that address for you to correctly and safely delete your object.
int& create_ref(){
int *x = new int;
*x =5;
return *x;
}
int* create_ptr(){
int *x = new int;
*x =5;
return x;
}
int create_sane_version() {
return 5;
}
int main(){
int& x = create_ref();
delete &x; // OK. Get address of x; same as deleting through a pointer pointing to its address
// x here refers to the newed object inside create_ref() (*x)
// Still begs the question of why you're painstakingly doing this
int* y = create_ptr();
delete y; // OK, but not optimal (the above isn't either)
// * not optimal == a bad way to do this
int leak = create_ref();
delete &leak; // DEFINITELY NOT OK. leak isn't the same as the newed object
// i.e. &leak != &create_ref();
// You're actually *copying* the object referred to by the returned
// reference. The returned reference gets lost.
int best_way_to_do_this = create_sane_version();
}
Will this cause a memory leak?
Yes, it will. You are allocating dynamic memory with the new statement with no corresponding delete to free it, ergo: you have a memory leak.
Is there somehow to delete it?
Of course there's: don't do dynamic memory allocation with naked pointers. In your case, why do you even need a reference at all?
int create(){
return 5;
}
int main(int, char*[]){
int y = create();
}
If you really need dynamic memory you can use std::shared_ptr and std::make_shared like this:
#include <memory>
auto create_ptr() {
return std::make_shared<int>(5);
}
int main(int, char*[]) {
std::shared_ptr<int> y = create_ptr();
}
Yes, this will create a memory leak. You allocate space with new, but never free it using delete.
If you want to create an object (or a primitive type) on the free store, you can return a pointer, and make the function caller for deleting the pointed-to object.
// Caller is responsible for deleting pointed-to int.
int* create_ptr()
{
// Hope that operator new does not throw std::bad_alloc
int* x = new int;
*x = 5;
return x;
}
A better approach would be to return a smart pointer, but that it outside the scope of this question.
Since you create memory on heap int *x = new int;, You need to explicitly delete it.
You can use shared pointers if you want to avoid track of all heap memory and deleting it explicitly.
Shared pointers keep track of all reference to a memory when last reference goes out of scope, memory pointed is deleted.