How to allocate the space without changing address in cpp? - c++

for example I have a struct now
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
I first have a pointer, but I do not allocate space for it, so just
TreeNode* p;
I want to allocate the space later, for example, in the other function, like below
void allo(TreeNode* p, int val){
p = new TreeNode(val);
}
allo(p,5);
// I want to get the original p here
But this new method change the address of the original p, which I could not trace it anymore. So is there a method to allocate without changing the address? The limitation is that I want to separate the definition and the allocation, just like above, for example, define outside a function and allocate inside the function.

You need to pass the parameter by reference, if you want to manage this pointer outside this function. Otherwise a copy of the pointer is passed to the function allo. This copying changes the pointer.
Try like this (if I understand the essence of the question):
void allo(TreeNode*& ptr, int val)
{
ptr = new TreeNode(val);
}

First of all:
You should NOT use raw owning pointers but smart pointers like std::unique_ptr<> or std::shared_ptr<> or RAII containers.
Your function allo() will do nothing to the pointer you pass to it because it takes the pointer by value (copy) and there is no way allo() could magically alter the adress of the pointer you pass it nor it's value. All that gets changed is the value of the parameter p which is local to your function, so the memory allocated effectively leaks.
Either, pass the paramter by reference so it can be altered within the function:
void allo(TreeNode* &ptr, int val)
{
ptr = new TreeNode(val);
}
TreeNode *p{ nullptr }; // you shouldn't leave pointers uninitialized
// ...
allo(p, 42);
or return a value:
TreeNode* allo(int val)
{
return new TreeNode(val);
}
// ...
TreeNode *p{ nullptr };
// ...
p = allo(42);
In both cases p points to the object allocated in allo() after the function call.

Related

Is the same memory allocated to all objects of class

I was trying to build a linked list without allocating memory dynamically. Note that I can build linked list using new operator.
The below code does not work. When I debugged it I found out (as much as I can understand) that Node a(n, head) is allocated at the same address in the memory every time so the a stores pointer to itself. If someone can explain to me, it would be of great help.
class Node {
public:
int val;
Node *next;
Node(int n, Node *ptr = NULL) {
val = n;
next = ptr;
}
};
class LinkList {
Node *head = NULL;
public:
void insertNode(int n) {
Node a(n, head);
head = &a;
}
void print() {
Node* ptr = head;
while (ptr != NULL) {
cout << ptr->val << endl;
ptr = ptr -> next;
}
}
};
int main() {
LinkList a;
a.insertNode(3);
a.insertNode(4);
a.print();
return 0;
}
No, the same memory is not allocated to all objects of a class... but the same memory is allocated for the local variables of every function. Once a function returns, all its local variables are destroyed, so its local variable memory is now unused, and the next function call will use it for its local variables. Hence every time you call insertNode it uses the same memory to hold a. And when you call print, it uses that same memory to hold ptr.
This is just what usually happens. Not all compilers do it the same way, so you can't rely on it. And if you had extra function calls between main and insertNode then insertNode's variables wouldn't get the same addresses as they do when main calls insertNode directly.
Also note that because you aren't allowed to use pointers to variables that were already destroyed, the optimizer is allowed to guess that when you use a pointer, it points to a variable that hasn't been destroyed, and sometimes this causes really weird behaviour. So you mustn't use pointers to destroyed variables, ever, even if you would be okay with getting the wrong data. The technical term is undefined behaviour.

C++ return type pointer to a structure leetcode

I need help with a return value for one of the leetcode questions I am attempting. I am instantiate a structure and then return the pointer to the structure.
TreeNode* deserialize(string data) {
TreeNode r(data[0] - '0');
TreeNode* root = &r;
return root;
}
But this gives me the error "stack use after scope"
I even tried to define root as a member variable to the class where this function is defined and I get "stack buffer overflow".
Here's the definition of TreeNode,
Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
Problem #297
Variables only exist in their respective scope. The scope of your variable r is the function deserialize, meaning that the memory automatically allocated on the stack upon entering the function will be deallocated upon leaving it.
The pointer to this structure you are returning will then be dangling, which means that it will point to uninitialized memory and may no longer be used.
To solve your problem, you will need this code:
TreeNode* deserialize(string data) {
return new TreeNode(data[0] - '0');
}
This will allocate the TreeNode instance on the heap and return a pointer to it. It will remain there, until you free it explicitely with delete, which you must do, unless you want your application to leak memory.
The problem is that you are creating r within the function deserialize(), essentially creating r on deserialize() stack and then returning a pointer to that object. However, after you exit deserialize() scope, it cleans up its stack, destroying r meaning that the pointer to r that you are returning is no longer pointing to a valid object and is instead points to uninitialized memory.
To fix this you need to use a heap allocated resource so you can maintain its lifetime beyond the deserialize() scope. You can use new but this means you have to manually manage the resources memory with new/delete pairs throughout the code which is super error prone. I would use std::shared_ptr so the resource is automatically allocated and deleted. std::shared_ptr has the added benefit of allowing you to have multiple copies of the resource.
#include <memory>
std::shared_ptr<TreeNode> deserialize(std::string data)
{
auto root = std::make_shared<TreeNode>(data[0] - '0');
return root;
}

C++: Will my pointer be dangling? How to assign a pointer a variable that exists in a function?

Im having difficulty describing this problem succinctly so be kind.
I have a Tree object that has an attribute root which is a pointer to a node object. When I initialize the Tree object the root is unknown so i assign it to a nullptr.
In a function after some computation I find the root node of a complete binary tree. I now want to hand this value over to my Tree.root pointer. However since this function is removed from the stack after execution and Tree.root pointer appears empty when I run it later.
class Tree{
public:
Node *root;
Tree(){
root = nullptr;
}
};
void worker(Tree *t){
// Perform some computation
// Since the var rootFound only exists in this function.
// After executing doesn't the memory address reallocated
// and therefore the root points to an unknown memory address?
t-> root = &rootFound;
}
int main(){
Tree t{};
Tree *ptr = &t;
worker(t);
// t pointer is null
return 0;
}
I was thinking I could assign the root pointer found by the function to the heap (use new ) and then assign my Tree pointer to it but Im not sure how to go about deleting this value. Also since any node has left and right Node pointer Im not sure if the pointers lose the memory address they are pointing too or if they too will be added to the heap.
I could also just be overthinking this.
Since you posted an incomplete code in your question, I will be forced to assume things.
I will assume your implementation look like this:
void worker(Tree *t){
Node rootFound;
// do stuff where eventually rootFound = something
t->root = &rootFound;
}
In this case, yes, t->root will point to a dead object once worker is finished.
I was thinking I could assign the root pointer found by the function to the heap (use new ) and then assign my Tree pointer to it but Im not sure how to go about deleting this value.
There is two kind of raw pointer in C++: owning pointer and non owning pointer.
If t->root is a owning pointer, it means you will call delete on it.
If t->root is not a owning pointer, it means you will not call delete on it.
Then if it is owning, you can totally do new Node{...} an assign to it.
If on the contrary it is not and you want to create an new tree in this function and delete it later, you will need to give an owning pointer back to the caller, something like this:
Node* worker(Tree* t) {
Node* rootFound = new Node{}; // create a whole new tree here
t->root = rootFound; // assign it to the tree
return rootFound; // return a owning pointer to the caller
}
Then, in your main:
int main(){
Tree t{};
Tree *ptr = &t;
Node* owning = worker(ptr);
// do stuff with t
// delete the owning pointer.
delete owning;
return 0;
}
Of course, there is a better way to separate owning and non owning pointer.
In modern C++, owning pointer are declared like this: std::unique_ptr<T> and non owning are written T* and assume you don't have to delete it.
If we change your data structure just a little bit to express what pointer is which, it would look something like this:
class Tree{
public:
// Here! Root is owning.
std::unique_ptr<Node> root;
Tree(){
root = nullptr;
}
};
// Tree is non-owning, so we write it just like before.
void worker(Tree* t){
// ...
}
The neat thing about std::unique_ptr is that is clears memory in its destructor so you don't have to worry about deleting:
int main() {
// make_unique will call new
std::unique_ptr<Node> node = std::make_unique<Node>();
// Here, unique_ptr will call delete
}
So in the end, Tree will clear up itself at the end of main:
int main(){
Tree t{};
Tree *ptr = &t;
// worker can do t->root = std::make_unique<Node>();
worker(ptr);
return 0;
// Here, t.root will call delete if not null
}

c++ vector of struct init

I am new to C++ and I am trying to initialize a vector of struct as code below.
struct Node{
int x;
Node *p;
int rank;
Node(int x) {
this->p = this;
this->x = x;
this->rank = 0;
}
};
int main() {
vector<Node> disjointSets;
for (int i = 0; i < 50; i++) {
Node a(i);
disjointSets.push_back(a);
}
}
In main, I try to create a Node a each time and push it into vector. But I later find there is an issue that a is always created at the exact same memory location. Therefore, the p, which is supposed to point to each Node itself will point to the last element after the loop. May someone explain why Node a is always created at same memory address and how to solve the issue?
You have undefined behavior, because you haven't defined a custom copy constructor for your Node class.
disjointSet.push_back(a); makes a copy of a. This is using the default copy constructor, which simply does an element-wise copy of all the member variables. So in the copy, p points to the address of the original Node, not itself. But that Node is destroyed when the loop iteration ends, so the pointer is no longer valid. It's implementation-dependent, but pretty common that the loop happens to use the same stack memory for a each time through the loop, so p in all the elements points to that same address, which is no longer a valid Node.
You need to define a copy constructor that sets p to the address of the copy:
Node(const Node &oldnode) {
p = this;
x = oldnode.x;
rank = oldnode.rank;
}
and a copy assignment operator:
Node& operator=(const Node &oldnode) {
if (&oldnode != this) {
x = oldnode.x;
rank = oldnode.rank;
}
return *this;
}
Your node's are created on the stack. And address which is assigned inside the constructor points to the stack. If you want the Nodes a constant address which doesn't change while they are moved/copied into the container you need to heap allocate them and use a vector of Node pointers. E.g. a vector<std::unique_ptr<Node>>.
You are not using heap memory. Storing the address of a local variable and trying to access it elsewhere is UB. If I'm correct, The answer for "why" the same memory space is taken for each iteration of the loop is implementation defined and in this case, it is reusing the same stack space.

C++ Setting Pointer Equal to shared_ptr

I'm trying to make a List class using the concept of linked lists, and while I was originally using the C++ standard new keyword, I decided to switch it out for the C++11 std::shared_ptr. However, I can't get the program to function properly when using smart pointers, as it crashes. Here are some bits of code before the change:
class List
{
public:
void push_back(...) {
Node *temp = new Node;
...
if (!head) {
head = temp;
return;
}
else {
Node *last = head;
...
last->next = temp;
}
}
...
private:
Node *head = nullptr;
};
And here's what it looks like with the change:
class List
{
public:
void push_back(...) {
std::shared_ptr<Node> temp(new Node);
...
if (!head) {
head = temp.get();
return;
}
else {
Node *last = head;
...
last->next = temp.get();
}
}
...
private:
Node *head = nullptr; // don't need this to be a smart ptr
};
I feel like the problem might be that head and last aren't dynamically allocated and maybe they need to be to work with a shared_ptr, but I'm not sure. What exactly am I doing wrong and how can I fix it? I really hope this isn't a duplicate because I can't seem to find anything that solves my problem. Thanks.
Edit:
Here's the Node struct:
struct Node{
int data;
Node* next;
};
The reason to have std::shared_ptr in the first place is to have std::shared_ptr take complete and full ownership of the pointer, and make it std::shared_ptr's responsibility to delete it, once the last reference to the pointer goes away. That's what std::shared_ptr is all about.
This means that once a pointer is placed into a std::shared_ptr, the std::shared_ptr now takes complete and full responsibility of managing the pointer. It owns it completely.
It, therefore, makes no sense to put a pointer into a std::shared_ptr ... and then immediately take it out:
head = temp.get();
There are reasons for the get() function to exist, but this isn't one of them.
In order to use std::shared_ptr correctly, everything must be a std::shared_ptr. head needs to be a std::shared_ptr:
std::shared_ptr<Node> head; // yes, it does need to be a smart ptr
Why does it need to be a std::shared_ptr? Well, if it's not, what do you think will happen when this:
std::shared_ptr<Node> temp(new Node);
Specifically, when this temp smart pointer gets destroyed, when this function returns? Well, since it will be the last std::shared_ptr that referenced this Node, it will happily delete it. The fact that you get() it earlier, and placed it into head doesn't matter. So now you have a head that points to a deleted Node. Hilarity ensues.
And this is why everything must be a std::shared_ptr. Not only head, but also Node's next member also needs to be a std::shared_ptr, too.
Now, there is a pitfall involving circular references, that comes into play when std::shared_ptr enters the picture. But that's going to be a different question.
Your main issue is that if you're going to use shared_ptr, best to use it all the way. Make next a shared_ptr instead of a raw one.
struct Node {
int data;
std::shared_ptr<Node> next;
}
What std::shared_ptr does under the hood is keep a count of how many references there are to a pointer. When you use copy constructors or operator= it increases a reference count. When an instance falls out of scope resulting in the destructor being invoked (or you give it a different pointer with operator=) the reference count decrements. When the count is zero the pointer is destroyed.
// pass by value invokes copy constructor (refcount + 1)
void myFunc(std::shared_ptr<MyClass> var) {
// Code using var
} // end of function invokes destructor (refcount - 1)
void run() {
std::shared_ptr<MyClass> ptr(new MyClass); // refcount = 1
myFunc(ptr); // refcount = 2
// After myFunc returns refcount = 1
}
int main() {
run(); // refcount = 1
// After run returns, refcount = 0 and the pointer is deleted
}
By using get() you introduce a pointer to memory that may be deleted at some point, regardless of whether or not that pointer is around. This can lead to segfaults as the raw pointers are pointing to memory that shared_ptr deleted.
This is because get() does not affect the reference count. How could it? It's not a shared_ptr any more so that class definition has no way of knowing what you do with it, or when it gets deleted. If get() increased the reference count there would be nothing to decrease it afterwards, and the memory would never be released. That's a memory leak!