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;
}
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.
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.
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.
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;
...
Related
I wanted to ask that when I don't write any copy constructor explicitly so the compiler automatically generates the copy constructor which performs shallow copy by default right?
So in the main() program when I changed the values of integers a, b and pointer p only the value of p changed and values of a and b remain unchanged in the copied object. Why the values of a & b didn't change too? My code is:
#include <iostream>
#include <string.h>
using namespace std;
class Dummy {
private:
int a, b;
int *p;
public:
Dummy() {
p = new int;
}
void setData(int x, int y, int z) {
a = x;
b = y;
*p = z;
}
void showData() {
cout << "a = " << a << " b = " << b;
cout << " p = " << *p << endl;
}
~Dummy() {
delete p;
}
};
int main() {
Dummy d1;
d1.setData(3, 4, 5);
Dummy d2 = d1;
d1.showData();
d2.showData();
d1.setData(6, 7, 8);
d1.showData();
d2.showData();
return 0;
}
The output of my program is:
a = 3 b = 4 p = 5
a = 3 b = 4 p = 5
a = 6 b = 7 p = 8
a = 3 b = 4 p = 8
What I'm saying is while the pointer of object d2 changed when I changed the values of object d1 then why didn't the values of a & b of object d2 changed too?
Also I'm using delete keyword in the destructor to delete the dynamically allocated pointer:
~Dummy() {
delete p;
}
But it's crashing my program instead. Why is that?
You've totally got it wrong - The idea of shallow copy. Actually, c++ does not have anything called deep copy built into itself. So, calling something shallow copy is a bit wrong. And just the use of these words shallow copy creates a lot of confusion too.
Now, let me explain, what happens when cpp performs initialization using assignment. cpp or c(while copying struct) has a concept called bitwise copy. In this concept, all the member variables of one object(struct object/class object - you can say either) is identically copied to another object. Now, it's totally wrong idea that, both objects point to same memory location. In actual, both object has their own memory location and of course, their variables occupy different memory spaces. For you, I have write some tests regarding memory. You would understand perfectly, if you just see the test and it's output:
#include <iostream>
#include <string.h>
using namespace std;
class Dummy {
int a, b;
int *p;
public:
Dummy() {
p = new int;
}
void setData(int x, int y, int z) {
a = x;
b = y;
*p = z;
}
void showData() {
cout << "a = " << a << " b = " << b;
cout << " p = " << *p << endl;
cout << endl; // an extra new line for readability of output
}
void showMemory() {
cout << "addr(a) = " << &a << " addr(b) = " << &b;
cout << " addr(p) = " << &p << endl;
}
~Dummy() {
*p = 100;
delete p;
}
};
// testing memory
void memoryTest() {
cout << "testing d1:" << endl;
Dummy d1;
d1.setData(3, 4, 5);
cout << "addr(d1) = " << &d1 << endl;
d1.showMemory();
cout << endl ;
cout << "testing d2:" << endl;
Dummy d2 = d1;
cout << "addr(d2) = " << &d2 << endl;
d2.showMemory();
}
int main() {
// memoryTest
memoryTest();
return 0;
}
And the output of the test was:
testing d1:
addr(d1) = 0x6dfed4
addr(a) = 0x6dfed4 addr(b) = 0x6dfed8 addr(p) = 0x6dfedc
testing d2:
addr(d2) = 0x6dfec8
addr(a) = 0x6dfec8 addr(b) = 0x6dfecc addr(p) = 0x6dfed0
This clearly shows that, the memory occupied by those two objects d1 and d2 are totally different.
Now, you may have another question remain: Then, why, when i write *p=8, it affects both d1 and d2?:
When you assign, Dummy d2 = d1;, we may say something happended like below(though, it's not actually happen when bitwise copy is applied, it's just for clarity):
d2.p = d1.p
So, we know that, d1.p and d2.p contains the same memory location(note: d1.p is a pointer. so, it does not contain any integer, rather it contains memory address of an int).
So, when you write *p = 8, you are telling the program to go to the memory location targeted by p and change the value of that memory location to 8.(note, here, you didn't change the content of d1.p, d1.p still contains the same memory location. rather, you just changed that memory location's content from 5 to 8). That's why when you call d2.p, you get the changed value. cause, d2.p contains the same memory location as d1.p.
Now, there may have one more question: Why your code crashes when you freed p in destructor?:
Now, let me first ask you, can you free a memory what is already freed. You can write the code, but the behavior is undefined. It may crashes your program or it may do nothing.
Well, in Dummy destructor you've written delete p;. Now, either d2 or d1 would be destroyed first. Let's assume, d2 is destroyed first. So, when d2's destroyer is called, p is freed. Then, d1's destroyer will be called and it'll also try to free p. But p is already freed. And in your case, the program meets a crash for this reason.
Hope, everything is clear to you now.
If anything is not clear about what I've described above, then ask questions, I will try my best to answer them too.
I have two classes, let's call them A and B
class A:
{
public:
//Some functions
A *getNewA() const;
private:
//some attributes
}
class B:
{
public:
//Some functions
private:
A &reftoA;
}
In the main code, I must generate a new A thanks to the A::getNewA() method. And this must go to B::reftoA, as written in class B.
Here is the A::getNewA() method :
A *A::getNewA()
{
A *newA = new A;
return newA;
}
OK. So now I call getNewA and want to store the results in reftoA, which is a reference to A. In a B function (which take a reference to A as parameter)
B::foo(A ¶mA)
{
reftoA = *(paramA.getNewA());
}
I thought this should have been working, but it won't.
Because when dereferencing, reftoA will always take the this object and not the new allocated object.
Let's be clearer and let's modify the functions to output the results
A * A::getNewA()
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return A;
}
void B::foo(A ¶mA)
{
reftoA = *(paramA.getNewA());
std::cout << "new generated pointer " << &reftoA << std::endl;
}
Here is one of the output :
New pointer : 004FFAEC
this pointer: 0069D888
New generated pointer : 0069D888 //Expected : 004FFAEC
I can't get this "new generated pointer" to be the same than the new pointer the A::getNewA() returns after having allocated the memory. Of course, I guess there is some point with dereferencing the pointer to store it in a reference.
I know reference are used with existing object. Maybe the new object A::getNewA() should allocate memory for won't work as I expected.
I could use pointer instead reference in B::foo(), I know, but I can't
I think I am misunderstanding something about refrence and pointer, but I don't know what.
Any help greatly appreciated
The problem is that you can not reassign a reference. You can change only the value of the referenced object.
So you have to initialize the reference in the initializer list of the constructor of the class B.
Take into account that there is a typo in your code snippet
A*A::getNewA()
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return A;
^^^^^^^^^
}
I think you mean
A*A::getNewA() const
^^^^^
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return newA;
^^^^^^^^^^^
}
Always try to provide a verifiable complete example.
Here is a demonstrative program
#include <iostream>
class A
{
public :
//Some functions
A* getNewA() const
{
A *newA = new A;
std::cout << "New pointer " << newA << std::endl;
std::cout << "this pointer" << this << std::endl;
return newA;
}
private :
//some attributes
};
class B
{
public :
B( const A& a ) : reftoA( *a.getNewA() )
{
std::cout << "&reftoA " << &reftoA << std::endl;
}
private :
A& reftoA;
};
int main()
{
A a;
B b( a );
return 0;
}
Its output is
New pointer 0x2b392afbec20
this pointer0x7ffd287ad0af
&reftoA 0x2b392afbec20
As you can see the values of the New pointer and &reftoA are equal each other.
To make it more clear consider a very simple example
#include <iostream>
int main()
{
int x = 10;
int y = 20;
int &r = x;
r = y;
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
std::cout << "r = " << r << std::endl;
std::cout << std::endl;
std::cout << "&x = " << &x << std::endl;
std::cout << "&y = " << &y << std::endl;
std::cout << "&r = " << &r << std::endl;
return 0;
}
The program output is
x = 20
y = 20
r = 20
&x = 0x7ffd88ad47a8
&y = 0x7ffd88ad47ac
&r = 0x7ffd88ad47a8
This statement
r = y;
did not force the reference to refer the object y. It just reassigned the value of the referenced object x.
References have to be initialized when they are created.
Yes, you are misunderstanding something.
getNewA() is returning a pointer. it's not a smart pointer, you want to look into those and that's all I'll say on the matter.
on returning a pointer, you must keep a reference to this pointer else you will be unable to delete it and you'll get a memory leak. Thus you MUST have somewhere A* a = A::getNewA() and then later, when you no longer need it delete a;
Where you need to pass a reference to A, you can do foo(*a) which will dereference the pointer and pass a reference to the object it's pointing to.
But in summary, for all new code, smart pointers; there's no excuse to not use them.
Side note: Your code example had a few other issues; such as getNewA wasn't static; I'm going to take the code as a working example of your understanding, and not a working example.
Edit: On re-reading your example, the getNewA is intentionally non-static. I think this question is actually an XY problem (ie you're asking a question you've forced yourself into but isn't your actual problem); but I hope this addresses your misunderstanding of pointers and references.
You are not returning the pointer in the getNewA-Method
A* A::getNewA()
{
A *newA = new A;
return A; // you are returning A and not newA
}
And if you want to reassign the reference to a you can use a std::reference_wrapper
class B :
{
public :
void foo(A& paramA) {
reftoA = *(paramA.getNewA());
}
private :
std::reference_wrapper<A> reftoA;
}
I have a question regarding the following code, which crashes. I am creating a local variable in testfunction() and then pushing it (variable "y") into a list. This variable has a member pointer "b" of object type Ball. As I understand, this local variable "y" is on the stack, so its' destructor will be called after testfunction() is completed. Also, as I understand, a vector "copies" an object into its' list. From what I've learned, it is best practice to delete a pointer in the destructor if one exists in its' class. So, there is "delete b" in the destructor of Example.
The issue that I am having is that the object y.b is being destroyed at the completion of testfunction(). In main(), I am able to see the value of "name" and the address of "b", but the object "b" has already been deleted. I would like to avoid this.
I think there is an issue with the design of the code/use of pointers vs references, etc. Please guide me in the right direction, I am an idiot!
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Ball
{
public:
int a;
Ball()
{
a = 0;
}
~Ball()
{
cout << "destroyed Ball()" << endl;
}
};
class Example
{
public:
string name;
Ball* b;
Example()
{
name = "";
b = NULL;
}
~Example()
{
cout << "destroying Example()" << endl;
delete b;
}
};
void testfunction(vector<Example>& list)
{
cout << "entered testfunction1()" << endl;
Example y;
y.name = "myName";
y.b = new Ball();
y.b->a = 5;
cout << "y.b->a = " << y.b->a << endl;
list.push_back(y);
cout << "exit testfunction1()" << endl;
}
void testfunction2()
{
cout << "entered testfunction2()" << endl;
Example* y = new Example();
cout << "exit testfunction2()" << endl;
}
int main() {
vector<Example> list;
testfunction(list);
//testfunction2();
if(list[0].b == NULL)
cout << "b is null" << endl;
else
cout << "b is not null" << endl;
cout << list[0].name << endl;
cout << list[0].b << endl;
cout << "list[0].b->a = " << list[0].b->a << endl;
return 0;
}
Since class Example has a pointer member and it tries to own a dynamically allocated resource, it needs non-default copy operations, in other words, it needs user-defined copy constructor and assignment operator.
Inside testfunction, when you copy y into vector, both local y and y copied to the vector point to very same Ball object. The local y is destroyed at the end of the function and Ball is deleted. However, that deleted Ball still pointed by the y in vector
void testfunction(vector<Example>& list)
{
// ...
Example y;
y.name = "myName";
y.b = new Ball();
y.b->a = 5;
list.push_back(y);
// ...
} // <-- destructor for Example y is called and y.b is deleted
Define a copy constructor and an assignement operator for your class Example.
These shall copy properly your object (creating a duplicated Ball object) when pushed back on the vector.
Example(const Example& a)
{
name = a.name; // attention no dynamic allocation
cout << "copy" <<endl;
if (a.b) {
b = new Ball(*a.b); // create a new duplicated Ball
}
else b = NULL;
}
The problem in your example is that the default copy constructor is called when you pushback the object. It copies memberwise and so the pointer to Ball is copied, not the object pointed to.
Yet another alternative could be to replace your Ball* with shared_ptr<Ball> (and accordingly, new Ball with make_shared<Ball>() and the delete b of the object with a b.reset()). The principle is that this smart pointer keeps track of the number of time the object pointed to is used, so that it will not delete it twice, but only when its no longer used anywhere.
I have few questions regarding below code
#include <iostream>
using namespace std;
class A
{
public:
A & add(A & b);
};
A & A::add(A & z)
{
A * a = new A();
A & b = *a;
cout << "Inside add, address of a: " << &a << endl;
cout << "Inside add, address of b: " << &b << endl;
cout << "Inside add, address of z: " << &z << endl;
A aa;
cout << "Inside, add, address of aa: " << &aa << endl;
return aa;
}
int main()
{
A *a = new A();
cout << "Original a: " << a << endl;
A & b = a->add(*a);
cout << "b: " << &b << endl;
return 0;
}
Q1. Inside main, line 3, a->add(*a), the same object pointed by pointer *a is passed. But inside the function A::add(A &), when i try to achieve the same effect via A &b = *a, i get a different object. Why is this so?
Q2. Inside A::add(A &), i return a non const reference to a local object aa and main gets the same memory address as the local reference. So this has the effect of extending the lifetime of local reference, beyond its scope.
Q3. Inside A::add(A &), i dereference *a multiple times, first via A &b = *a and then by return *a. In both cases, the memory address is always the same. How is this happening? You can check the output of &b inside A::add(A &)and the result of A &b = a->add(*a)
UPDATE:
The issue related to Q1 was that i was doing cout << &a, when i should have been doing cout << a
To eliminate return value optimization, i compiled with -fno-elide-constructors. I am using g++.
A1: You created a new *a with A* a = new A() The a in main is different than the a in A::add. The a in main is referenced by the variable z
A2: No, you created a on the heap, so it is going to last until you call delete on that variable
A3: A dereference does not change the memory location that is stored in the pointer, it just gets the value stored in that location. A reference is more like an alias. So &b is like saying &(*a)
Following results are very interesting and I am having difficulty understanding them. Basically I have a class which has an int:
class TestClass{
public:
int test;
TestClass() { test = 0; };
TestClass(int _test) { test = _test; };
~TestClass() { /*do nothing*/ };
};
A test function which accepts a pointer of TestClass
void testFunction1(TestClass *ref){
delete ref;
TestClass *locTest = new TestClass();
ref = locTest;
ref->test = 2;
cout << "test in testFunction1: " << ref->test << endl;
}
This is what I am doing in main:
int main(int argc, _TCHAR* argv[])
{
TestClass *testObj = new TestClass(1);
cout << "test before: " << testObj->test << endl;
testFunction1(testObj);
cout << "test after: " << testObj->test << endl;
return 0;
}
I was expecting output to be:
test before: 1
test in testFunction1: 2
test after: 1
But I get the following output:
test before: 1
test in testFunction1: 2
test after: 2
Can someone explain this. Interesting thing is that changing testFunction1 to:
void testFunction1(TestClass *ref){
//delete ref;
TestClass *locTest = new TestClass();
ref = locTest;
ref->test = 2;
cout << "test in testFunction1: " << ref->test << endl;
}
i.e. I do not delete ref before pointing it to new location, I get the following output:
test before: 1
test in testFunction1: 2
test after: 1
I would really appreciate if someone can explain me this strange behavior. Thanks.
When you access the object after deleting it, the behaviour is undefined.
The behaviour that you see follows from the memory allocation algorithm in your system.
That is after deleting your first testclass object, you allocate memory for a new object. The runtime simply reuses the memory.
To check what is going on, print the values of the pointers:
void testFunction1(TestClass *ref){
cout << ref << endl;
delete ref;
TestClass *locTest = new TestClass();
cout << locTest << endl;
ref = locTest;
ref->test = 2;
cout << "test in testFunction1: " << ref->test << endl;
}
You get a copy of the pointer to the object in testFunction1(), so when you assign to it, the original value of the pointer in main() does not change
Also, you are deleting the object (by calling delete in testFunction1()) to which the original pointer (in main()) is pointing, but as the value in main() is not updated, you are accessing an invalid object -- the fact that you can read the value that you set in testFunction1(), is a coincidence and cannot be relied on
The fact that you correctly read the original value in the second case (when you don't call delete) is because the original object has not been changed (you change a new one in testFinction1 and the pointer to it in main is the same (as explained above) and the object is still alive
in this case , you just got the new object at the same address with the old one you delete.
actually testObj became a dangling pointer after you call testFunction1.
void testFunction1(TestClass *ref){
delete ref;
TestClass *locTest = new TestClass();
cout << "locTest = " << locTest << endl;
ref = locTest;
ref->test = 2;
cout << "test in testFunction1: " << ref->test << endl;
}
int main(int argc, char * argv[])
{
TestClass *testObj = new TestClass(1);
cout << "test before: " << testObj->test << endl;
cout << "testObg = " << testObj << endl;
testFunction1(testObj);
cout << "test after: " << testObj->test << endl;
cout << "testObg = " << testObj << endl;
return 0;
}
Output is :
test before: 1
testObg = 0x511818
locTest = 0x511818
test in testFunction1: 2
test after: 2
testObg = 0x511818
After this instruction:
TestClass *testObj = new TestClass(1);
you have allocated a new memory area containing a TestClass object, whose address (let's call it maddr) is stored into testObj.
Now, this instruction:
cout << "test before: " << testObj->test << endl;
outputs 1, as expected.
Inside testFunction1() you have a local variable called ref, which is a pointer containing the value maddr.
When you delete ref, you deallocate the area of memory containing a TestClass object, whose address is maddr.
Then you allocate a new memory area:
TestClass *locTest = new TestClass();
and locTest contains its address, let's call it m1addr.
Then you use ref to access the memory area at m1addr and change the int test value to 2.
This instruction:
cout << "test in testFunction1: " << ref->test << endl;
outputs 2 as expected.
Now, back to main, you have lost any handler to the area containing a TestClass object whose address is m1addr (that is, you are leaking memory) and the area pointed to by testObj is not allocated anymore.
When you use testObj again, you access an area of memory starting at maddr, which has been cleaned. The effect of accessing testObj->test is undefined behavior.
What you experience could be do to the fact that when you run your code maddr == m1addr, but this can only happen by chance, you cannot rely on this.
Odds are the new object (with a 2) is being created where the old deleted object (with a 1) used to be. Your original pointer still points to that location so when you access it you accidentally access the new object (with a 2).
TestClass *ref in the parameter to testFunction1 and TestClass *testObj in main are 2 different pointers to the same thing, they are not the same pointer though. If you want to delete and reallocate an object inside a function/method you can use a pointer to a pointer as the parameter.
As others have mentioned , after testfunction1 you're accessing an object that was deleted within testfunction1 which as also mentioned is undefined behaviour. The memory being pointed to by the dangling pointer was released during the delete but the contents are likely to still be there until the memory location is reallocated during another call to new. So you are using unallocated space that could be overwritten very easily at anytime.
Hope this helps