Reputation: 3
I encountered a problem which I am baffled with. This pertains to whether I choose to store an object, or a pointer to it.
This is my class:
class Test {
public:
std::string abc;
int x;
Test(std::string def, int y) {
abc = def;
cout << abc << endl; //THIS ALWAYS GIVES "ghi"
x = y;
}
};
Storing it as a pointer:
Test* T1 = &Test{ "ghi", 100 };
cout << T1->abc << endl; //**THIS IS BLANK -- WHY!?**
cout << T1->x << endl; //THIS GIVES 100
Storing it as an object itself:
Test T2 = Test{ "ghi", 100 };
cout << T2.abc << endl; //THIS GIVES "ghi"
cout << T2.x << endl; //THIS GIVES 100
I'm relatively new to C++ but based on my understanding, T1->abc should dereference the pointer T1 (and therefore I have a Test object), and then access the member abc of that Test object. Since I already created the object, it should be "ghi". But this gives blank instead.
Apparently, this applies only to the string member and not the integer member, as T1->x works fine.
And the problem doesn't exist when I store the object instead of a pointer to it, as shown by the object T2.
I have checked that during construction of T1 and T2, abc is always "ghi" inside the constructor. Somehow, after construction, the string just disappears.
Also, based on what I read, abc = def copies the string content and not the pointer, so it probably isn't a scope issue.
https://msdn.microsoft.com/en-us/library/b930c881.aspx makes it very clear that in either case, whether -> or . is used, assignment can be made.
Searching Google and stackoverflow did not help. Hence yours appreciated. Thanks in advance.
class Test {
public:
std::string abc;
int x;
Test(std::string def, int y) {
abc = def;
x = y;
}
};
int main() {
Test* T1 = &Test{ "ghi", 100 };
cout << T1->abc << endl; //THIS IS BLANK -- WHY!?
cout << T1->x << endl; //THIS GIVES 100
Test T2 = Test{ "ghi", 100 };
cout << T2.abc << endl; //THIS GIVES "ghi"
cout << T2.x << endl; //THIS GIVES 100
return 0;
}
Upvotes: 0
Views: 327
Reputation: 1796
Test* T1 = &Test{ "ghi", 100 };
Please don't do this. This is exactly what's causing your problem. Instead use
Test* T1 = new Test("ghi", 100);
Because the first way created a reference to a temporary object, which disappears before you try to get the string for printing.
It works for the non-pointer because you're giving the temporary object to a new object.
don't remember to delete (because you've used new)
delete T1;
Or, as πάντα ῥεῖ pointed out, what would be safer, and better c++ coding practice, would be to use a smart pointer. The most relevant one that comes to mind is unique_ptr.
std::unique_ptr<Test> T1(new Test());
std::cout << T1->abc << std::endl;
...
Upvotes: 1
Reputation: 310980
This code snippet
Test* T1 = &Test{ "ghi", 100 };
cout << T1->abc << endl; //**THIS IS BLANK -- WHY!?**
cout << T1->x << endl; //THIS GIVES 100
has undefined behaviour because after statement
Test* T1 = &Test{ "ghi", 100 };
temporary object Test{ "ghi", 100 } will be deleted and the pointer becomes invalid.
A valid code could look the following way
Test* T1 = new Test{ "ghi", 100 };
cout << T1->abc << endl;
cout << T1->x << endl;
delete T1;
Or instead of the pointer you could use a constant reference to the temporary object. For example
const Test &T1 = Test{ "ghi", 100 };
cout << T1.abc << endl;
cout << T1.x << endl;
The temporary object will be alive while the reference will be alive.
Upvotes: 1
Reputation: 12058
This construct:
Test{ "ghi", 100 };
creates temporary variable, that you are trying to point to. This is just wrong.
If you want to store it using pointer:
Test* T1 = new Test{ "ghi", 100 };
cout << T1->abc << endl; //This is not blank anymore
cout << T1->x << endl;
delete T1; //Do NOT forget this!
By the way, if you are wondering, why this line:
cout << T1->x << endl;
was still evaluating to 100: when object is destroyed, all its members are also destroyed (in terms of calling their destructors). Since x
is an int
, its destructor in no-op and content of memory occupied by it does not change.
On the other hand, abc
is and std::string
, which frees allocated memory during destruction - so T1->abc
was referring to an empty string.
Upvotes: 2
Reputation: 1
Test* T1 = &Test{ "ghi", 100 };
The temporary rvalue of Test{ "ghi", 100 }
immediately goes out of scope and ceases to exist after this statement.
Thus dereferencing it like
cout << T1->abc << endl;
simply calls Undefned Behavior on a dangling pointer.
Upvotes: 1