0

I am implementing a linked stack of strings in C++, mainly for fun. Every object of the list is a Node instantiation, and the list itself is an instance of StackOfStrings. Right now I instantiate a new Node using new and everything works fine, but I can't seem to figure out how to instantiate a Node on the stack and refer to it at a later point in the code.

I tried changing first = new Node; with first = &Node(); inside the push() method, but then I get a run-time std::bad_alloc error when I call the pop() method. My guess is that this Node gets created on the stack and is destroyed as soon as the program exits the push() method. So my question is: is there a way I can create assign to first a Node created on the stack and retain it for later use?

I am including the bare bones of the code, I added a comment next to the line that is causing me problems.

class StackOfStrings
{
public:
    StackOfStrings() {}; // Could be omitted, default constructor

    void push(std::string item)
    {
        Node* old_first = first;
        first = new Node;         // *** my question revolves around this line ***
                                  // ***    "first = &Node()" does not work    ***
                                  // ***  how can I have a Node on the stack?  ***
        first->setItem(item);
        first->setNext(old_first);
    }

    std::string pop()
    {
        std::string item = first->getItem();
        first = first->getNext();
        return item;
    }

private:
    Node *first = nullptr;
};

For completeness, this is the Node class:

class Node
{
public:
    std::string getItem() { return item; }
    Node* getNext() { return next; }
    void setItem(std::string item) { this->item = item; }
    void setNext(Node *node) { this->next = node; }

private:
    std::string item;
    Node* next = nullptr;
};

edit: by mistake I wrote *Node instead of &Node. I updated the question.

edit 2: a little experiment I tried:

  • I called the push() method of StackOfStrings to insert the word "hello" inside the linked list.
  • inserted a breakpoint inside the setItem() method of Node to check that the world "hello" was saved in memory. Indeed, at memory address 0x00FFF900 I found the values 68 65 6c 6c 6f, which corresponds to "hello" in ASCII
  • I then placed another breakpoint inside the call to getItem() in order to analyze the same memory address again. What I found now a0 fb ff 00 28 which is garbage and certainly not "hello".
giacomo-b
  • 394
  • 3
  • 13
  • 4
    No, the stack is temporary and any values on it become invalid at the end of your function. Why do you want to use the stack rather than the heap? – Alan Birtles Apr 13 '20 at 12:50
  • @AlanBirtles thank you. For no particular reason really, I was just curious to see if it was possible to do so somehow. – giacomo-b Apr 13 '20 at 12:53
  • @giacomo-b Can you give us the actual error and why do you want your Node object allocated on stack (As @AlanBirtles has mentioned stack variables are destroyed at the end of the function). The syntax `first = *Node()` is not valid C++ syntax. – h4ckthepl4net Apr 13 '20 at 12:57
  • The next time you call a routine it is using that stack memory for something else. That's how stacks work. – stark Apr 13 '20 at 13:05
  • @h4ckthepl4net sure. As I said, I get a `std::bad_alloc`: *Unhandled exception at 0x757D4192 in stacks.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x008FF430. occurred*. – giacomo-b Apr 13 '20 at 13:06
  • @h4ckthepl4net sorry about `first = *Node()`, that was just a mistake I made while writing the question. What I actually wrote in the code is `first = &Node()`. I updated my question with the right syntax. Please also check my last edit to the question for additional information about the memory status. I guess it is indeed due to the fact that the value is invalidated, as others pointed out. – giacomo-b Apr 13 '20 at 13:17
  • @stark thank you. I analyzed the memory and this is indeed the case. It is probably pretty obvious to you but, if you are interested, I added the memory values to my question. – giacomo-b Apr 13 '20 at 13:18
  • @500-InternalServerError I actually mean *the* stack. I wrote a pretty detailed question, I was trying to allocate an entry of *a* stack of string on *the* stack. – giacomo-b Apr 13 '20 at 13:46
  • 1
    @giacomo-b "What I found now a0 fb ff 00 28 which is garbage and certainly not "hello".". As mentioned that's because the local variable is destroyed when function exits and the memory is freed. If you have some problem that your'e trying to solve this way, than I think you need to give more information about the problem ([XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)) and maybe we can help you find correct solution, otherwise allocating variables on stack and using them when the stack frame is destroyed is a very bad idea and I think you cant get it work. – h4ckthepl4net Apr 13 '20 at 14:02
  • Thank you @h4ckthepl4net, I am actually not trying to solve any problem, I was just trying to experiment. I used to code in Python and about a year ago made the transition to C++, which is of course much different from higher-level programming languages. I love the freedom that C++ gives you when it comes to handling the memory, and my (mostly scientific) applications saw an incredible performance boost from the moment I switched. Unfortunately, having used the language for only a year or so, I am still not familiar with some of the features. So thank you, these answers made everything clear. – giacomo-b Apr 13 '20 at 15:22
  • @giacomo-b No problem mate :) – h4ckthepl4net Apr 13 '20 at 20:00

2 Answers2

2

First this is a very very bad idea.

Second you shouldn't take address of a temporary because it will be destroyed once the semicolon is reached leaving your pointer pointing to an invalid object . I think this line shouldn't even compile ! Are you using any visual c++ extension ?

first = &Node();

you construct a temporary on the stack by calling Node() then you bind its address to first pointer then the temporary gets destroyed .

Third the exception you get is because of this :

your getItem() method returns by copy rather than by reference so once called in pop() on a dangling pointer first the std::string copy constructor is called to copy the member std::string item which is invalid because it was destroyed from the beginning .

In the copy constructor of std::string it reads the size of the other string which happens to be some random bytes on the stack since the original string was destroyed .

This number is very big that Windows can't allocate memory for it on the heap so an exception of type std::bad_alloc is thrown

If the number was small enough but not smaller than std::string internal stack array , you might get an access violation because the copy constructor will attempt to copy buffer from an invalid memory address . Or even worse ! you might corrupt the heap or read some random bytes if this chunk was related to any other object in the program

dev65
  • 1,440
  • 10
  • 25
  • Thank you for your answer, this really clarifies what is going on! Actually no, I am not using any particular extension. I usually compile on Linux using g++ but today I was using my other Windows partition. I should try to compile with g++ as well and see what happens. Why do you think it shouldn't compile? I mean, I get what that what I am writing is incorrect, but am I not just assigning an address to a pointer? Isn't this acceptable from a compiler perspective? – giacomo-b Apr 13 '20 at 13:41
  • yes the compiler shouldn't allow this code : https://stackoverflow.com/questions/2280688/taking-the-address-of-a-temporary-object – dev65 Apr 13 '20 at 13:43
1

How can I allocate memory on the stack for a pointer to an object?

By creating an automatic variable. Like this:

void foo() {
    Node* ptr; // this pointer is allocated on the execution stack

is there a way I can create assign to first a Node created on the stack

Sure. Create an automatic Node, and use the addressof operator:

Node node;
StackOfStrings sos;
sos.first = &node;

This simple example violates access specifiers of your class. You may want to for example pass the pointer to the constructor in order to avoid needing to change the access specifier.

and retain it for later use?

Automatic variables (i.e. all variables allocated on the execution stack) are destroyed at the end of their scope. No exceptions. If later use is within that scope, then there is no problem. If later use is outside of that scope, then wanting to use the execution stack is a mistake.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Thank you for your answer, I have a question about your example though. What do you mean by `sos.first = &first`? I am not referring to the access violation of my specific case, assume everything is public if it makes it easier. But I am wondering what `&first` refers to, since you haven't defined `first`. Thank you. – giacomo-b Apr 13 '20 at 13:44
  • @giacomo-b sorry, I had changed my mind on the name of the variable, but forgot to update that line. It's supposed to be `&node` – eerorika Apr 13 '20 at 13:46
  • Ok now everything makes sense! Thanks – giacomo-b Apr 13 '20 at 13:46