1

This code uses a while loop to get user input and execute the appropriate command - I've reduced it to 2 commands for sake of brevity.
The Oblock object is created correctly (command "O"), as is the pointer to the base class. It appears that the calls to both objects work correctly as well. However, after returning to the while loop, the pointer to the object appears to be lost, and attempting to access its members (command "t") causes a segfault. I've included the example code below - my questions are afterwards.

#include<vector>
#include<iostream>
#include<string.h>

using namespace std;

class Tetramino {
    private:
        int squareSize;
        vector<string> myShape;
    public:
        void setValues(int size) {
            squareSize = size;
            myShape = vector<string> ((size*size), ".");
        }
        string getValues(int i) {
            return myShape[i];
        }
        int getSize() {
            return squareSize;
        }
};

class Oblock : public Tetramino {
    public:
    Oblock() {
        setValues(2);
    }
};

main () {
    string input;
    bool runProgram = true;
    Tetramino *pBlock;

    while (runProgram) {
        cin >> input;
        if (input == "O")
            {
                Oblock myBlock;
                cerr << "0thi: " << myBlock.getValues(0) << endl;
                Tetramino *pBlock = &myBlock;
                cerr << "0thi: " << pBlock->getValues(0) << endl;
            }
        if (input == "t")
            {
                cerr << "0thi: " << pBlock->getValues(0) << endl;
            }
        }
    return 0;
}
  • Are objects deconstructed upon exiting the if statements?
  • Is there perhaps a better way to repeatedly get user input?

Thanks in advance for any advice! I searched for questions similar to this one and couldn't find one appropriate for my needs.

  • `` does not declare `std::string`, it declares C functions like `strcpy`. `` is the correct header for using `std::string`. (But your code probably compiled because `` often indirectly includes ``.) – aschepler May 17 '14 at 05:16

4 Answers4

3

Tetramino *pBlock is local within its scope. You're shadowing over the one in main with the one within the if.

Also, myBlock is local and will be destructed - you'll have a dangling pointer. You should allocate with new (and delete...)

Instead of Tetramino *pBlock = &myBlock; do pBlock = new Oblock; when you handle the "O" input (and handle delete pBlock of the previous one).

littleadv
  • 20,100
  • 2
  • 36
  • 50
1
 if (input == "O")
 {
     Oblock myBlock;
     cerr << "0thi: " << myBlock.getValues(0) << endl;
     Tetramino *pBlock = &myBlock;
     cerr << "0thi: " << pBlock->getValues(0) << endl;
 }

An object with automatic storage duration (commonly called a function-local variable) has a lifetime beginning after its declaration and ending at the end of the nearest enclosing block } token. So myBlock is destroyed at the end of this if statement, and can't be used again.

Also note that you have declared two different pointers named pBlock. Assigning the inner one does nothing to the earlier one, which is still uninitialized.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • Thanks for the help! Is the behavior unique to pointers? If I run a similar program with a standalone int instead of a pointer, it seems to work fine (sorry the formatting is wonky): ` main () { int p = 0; string input; bool doWhile = true; cout << p << endl; while (doWhile) { cin >> input; if (input == "O") { for (int i = 0; i < 5; ++i) ++p; } if (input == "P") { cout << p << endl; } } }` –  May 17 '14 at 19:31
  • Well in that case, you declare `p` in the outermost block, so it's fine. – aschepler May 17 '14 at 20:46
  • Oh, I follow. So if I've declared it but haven't defined it it's not going to work, but so long as it's got a definition I'm good to go. Thanks! –  May 18 '14 at 16:45
1

Answering your first question: Yes, the statement

Oblock yblock;

Creates an instance of Oblock on the stack. It is destroyed when the code leaves the respective block, so any pointers to it become invalid after that. To create an object that lives as long as you wish, use new to create the object on the heap.

PMF
  • 14,535
  • 3
  • 23
  • 49
  • So, for the purposes of variable lifetime and modification, if statements work the same as functions? Like, I could define a variable j outside an if statement, and create a new variable j inside an if statement that is independent from the first? Also - are all objects created on the stack unless they are created with new? –  May 17 '14 at 05:45
  • Objects created inside a function and not with `new`, have *automatic* storage (this is sometimes called 'the stack'). They get destroyed when the scope they were declared in ends. The statement block following an `if()` is a new scope. – M.M May 17 '14 at 05:50
  • Rather than using `new` as some have suggested, make `myBlock` be outside the loop, but just don't use it if you don't need to. – M.M May 17 '14 at 05:51
  • @user3566909: Yes, but not the "if" is actually the relevant part, but the braces { and } which make up a _statement block_. That also works with for, while, do or similar constructs, in fact even without that. You may place a block anywhere where a single statement is allowed. – PMF May 17 '14 at 11:00
  • @MattMcNabb Thanks, I understand what you're saying. I declared it after the subclass definitions as you suggested and everything seems to be working fine - thanks! –  May 17 '14 at 19:35
0

Your pointer becomes garbage after myBlock goes out of scope (where the if statement closes) which will be causing the segmentation fault when you try to access it later

if(input == "O"){
    Oblock myBlock;
}
^^^^ right here myBlock becomes garbage

Also, if a user inputs "t" before "O" it will cause a segmentation fault because they will be trying to access an uninitialized pointer. You should probably get that looked at.

RamblingMad
  • 5,332
  • 2
  • 24
  • 48
  • Thanks for the help! The inputs are intended for use by another program that will not put a "t" before "O". However, your point still stands from a design standpoint - can you think of a failsafe way to implement input like this? Nothing comes to mind, but I'm not all that great. –  May 17 '14 at 19:26
  • Just check if they've put in an "O" yet and if they haven't, either ask for different input (probably ask for an "O"), throw an exception or just make "t" implicitly call "O" – RamblingMad May 17 '14 at 21:01