Alright so I've been getting deeply into C++ as of late and I'm getting everything down. Pointers are finally starting to make sense as far as when I should use them, how to implement them correctly, etc.
However, there was one little question about the fundamental use of pointers that I still had that needed answered. I'll jump right to the code:
With the following class A and function foo(A* bar)...
class A
{}
void foo(A* bar)
{}
... what's the difference between the following calls to foo?
A* a;
A b;
foo(a);
foo(&b);
They both compile fine, and as far as I can remember I haven't had any issues with them.
I think that A b; is instantiated right there, whereas A* a; needs to be created with new (since it hasn't actually created the object, it's just held a 4-byte long reference to a potential A object).
I could, if I am thinking about this correctly, do a = b; (EDIT make that a = &b) and then successfully pass a to foo. But, if I don't do a = &b and foo tries to read the (non-existent) object pointed to by a, it will causes runtime errors.
Also, if the above is correct, then it's assumed I can successfully call foo(&b); just fine.
Am I correct?
Thanks!
Yes, Your understanding is correct.
foo(&b);
passes address of an already existing object of type A as an parameter to function foo().
foo(a);
passes a pointer to the type A as function parameter. To be able to do anything meaningful it must point to a valid A object.It can be done in two ways:
Allocating object on stack:
Create an object of the type A on stack(local storage) & make the pointer a point to this object:
A* a;
A b;
a = &b;
Dynamic Memory allocation:
A *a = new A;
Though, Once you do a dynamic memory allocation you will have to remember to free the alloated memory explicitly after use, or you will have a memory leak:
delete a;
Note that it is always better to avoid dynamic allocations as far as possible, and if you must do so, use Smart pointers instead of raw pointers.
You can't do a = b.
It would have to be a = &b, to set a to the address of b.
You are also correct about the memory management: b is allocated on the stack, while a allocates space only for a pointer and leaves creating the actual object to you.
foo(&b) will work file, where the behavior of foo(a) would be undefined before you initialize *a (such as via a = new A()).
In C++, pointers are first-class objects. A pointer isn't just an invisible reference that needs an associated object to have an identity. That's how Java/C# references work (or most other languages, really), but a pointer is an object in itself.
So A* a declares a pointer. It doesn't point to anything, and it doesn't have to point to anything. And if/when it points to something, it doesn't need to own that something.
So you don't need to do a = new A(). You can do a = &b as well (to have a contain the address of the object b. Or it can point to any other object of type A as well. A pointer is just an object that stores an address. It's key to your understanding that you throw away the notion that it "has an object" which "needs to be created".
It is an object, which contains an address (or it contains the special value null), and if it contains an address, there may or may not be an object of type A at that address.
You are mostly correct. You should not assume that pointers are 4 bytes (for example, it might be 8 on amd64 systems). Also, your assignment should be a = &b; (note the addition of the address operator). Other than that, it sounds pretty reasonable.
Related
Here's the line of code:
A a = static_cast<A>(*(new A)); // ?
It compiles fine on 64bit clang at least.
But where is the memory actually allocated and what happens to variable a?
Besides there's no static cast needed, the memory allocated with new A simply leaks. You have lost access to that pointer and can never delete it properly anymore.
But where is the memory actually allocated and what happens to variable a?
Variable a is destroyed as soon it leaves scope as usual.
A a = static_cast<A>(*(new A)); // ?
This does the following.
(new A) // allocate a new A on the heap
*(new A) // the type is now A instead of *A
static_cast<A>(*(new A)) // makes it into an type A from type A in an potentially unsafe way (here it is a no-op as they are the same type)
A a = static_cast<A>(*(new A)); // copies the (default) value of A to a
; // leaks the allocted A as the last reference to it disappear.
I'm going to answer this question on the assumption that this line of code appears inside a function. If it appears elsewhere, the bit about the "stack" is inaccurate but everything else is still accurate.
This line of code compiles to four operations, which we can write as their own lines of C++ to make things clearer. It makes two allocations, in two different places, and one of them is "leaked".
A a;
{
A *temp = new A;
a = *temp;
}
The first operation allocates space for an object of type A on the "stack", and default-initializes it. This object is accessible through the variable a. It will be automatically destructed and deallocated no later than when the function returns; depending on surrounding context, this might happen earlier, but in no case while the variable a is in scope.
The second operation allocates space for another object of type A, but on the "heap" instead of the "stack". This object is also default-initialized. The new operator returns a pointer to this object, which the compiler stores in an temporary variable. (I gave that variable the name temp because I had to give it some name; in your original code the temporary is not accessible by any means.) This object will only ever be deallocated if, at some point in the future, the pointer returned by new is used in a delete operation.
The third operation, finally, copies the contents of the object on the heap, pointed to by temp, into the object on the stack, accessible via the variable a. (Note: the static_cast<A>(...) that you had written here has no effect whatsoever, because *temp already has the type A. Therefore, I took it out.)
Finally, the temporary variable holding the pointer to the object on the heap is discarded. The object on the heap is not deallocated when this happens; in fact, it becomes impossible for anything ever to deallocate it. That object is said to have leaked.
You probably wanted to write either
A a;
which allocates an object on the stack and does nothing else, or
// note: C++11 only; C++03 equivalent is std::shared_ptr<A> a(new A());
auto a = std::make_shared<A>();
which allocates an object on the heap and arranges to reference-count it, so that it probably won't leak. (There are a few other things you might have meant, but those are the most likely.)
For a simple definition of A, it is equivalent to:
A a(*new(A));
An A is dynamically allocated on the heap, a is copy constructed on the stack, and the dynamic allocation is leaked.
For a trivial definition of A the overall effect might as well be:
new A;
A a;
this copy implements the leak without the wasteful copy operation or the messy, redundant cast :)
I am reading this,
http://www.informit.com/articles/article.aspx?p=31529&seqNum=5
and author explain three types of smart pointer design (see pictures at the end of the post).
I believe current GCC, CLang and probably Visual C++ uses smart pointers with control block.
I can imagine why intrusive reference counting is not used, but what is the problem with second implementation - smart pointer with pointer to pointer block? There should be two pointer de-references, but smart pointer object size will be just half.
smart pointer with control block
smart pointer with pointer to pointer block
smart pointer with intrusive reference counting
One important reason is performance, shared_ptr::get() doesn't have to dereference a pointer to find the object address if it's stored directly inside the shared_ptr object.
But apart from performance, the smart pointer with pointer to pointer block implementation wouldn't support all the things you can do with shared_ptr e.g.
std::shared_ptr<int> pi(new int(0));
std::shared_ptr<void> pv = pi;
std::shared_ptr<int> pi2 = static_pointer_cast<int>(pv);
struct A {
int i;
};
std::shared_ptr<A> pa(new A);
std::shared_ptr<int> pai(pa, pa->i);
struct B { virtual ~B() = default; };
struct C : B { };
std::shared_ptr<B> pb(new C);
std::shared_ptr<C> pc = std::dynamic_pointer_cast<C>(pb);
In these examples pv, pai and pb store a pointed that is not the same type as the pointer owned by the control block, so there must be a second pointer (which might be a different type) stored in the shared_ptr itself.
For pv and pb it would be possible to make it work, by converting the pointer stored in the control block to the type that needs to be returned. That would work in some cases, although there are examples using multiple inheritance that would not work correctly.
But for the pai example (which uses the aliasing constructor) there is no way to make that work without storing a pointer separate to the one in the control block, because the two pointers are completely unrelated types and you can't convert between them.
You said in a comment:
I see and in case of make_shared, second pointer points to the address internal to the allocated block. (I actually tried this already and it seems that way)
Yes, that's correct. There is still a second pointer, but both poitners refer into the same block of memory. This has the advantage that only one memory allocation is needed instead of two separate ones for the object and the control block. Additionally, the object and control block are adjacent in memory so are more likely to share a cache line. If the CPU has got the ref-count in its cache already then it probably also has the object in its cache, so accessing them both is faster and means there is another cache line available to be used for other data.
I am little bit curious about that why memory is not allocated to a class or structure when we create pointer type object ?
For example :-
class A
{
public:
void show()
{
cout<<" show function "<<endl;
}
};
int main()
{
A *a;
a->show();
return 0;
};
Because pointers and memory allocation are a priori completely unrelated. In fact, in modern C++ it’s downright bad to use pointers to point to manually allocated memory directly.
In most cases, pointers point to existing objects – that’s their purpose: to provide indirection. To reiterate: this is completely unrelated to memory allocation.
If you want to directly have an object you don’t need a pointer: just declare the object as-is (= by value):
A a;
a.show();
This code:
A *a;
a->show();
just declares a pointer of type A*. Pointer alone is nothing but a variable that holds an address of some memory in it, i.e. it just points somewhere, nothing else. Pointer of type A* means that it points to memory, where an instance of type A is expected to be found.
a->show(); then just relies on this "expectation", but in fact it just uses uninitialized pointer, which results in undefined behavior.
This could be either solved by dynamically creating an instance of A:
A *a = new A();
a->show();
(which however gives you unpleasant responsibility for cleaning up this memory by calling delete a;) or even better: using an object with automatic storage duration instead:
A a;
a.show();
In the second case, an instance of type A is created automatically and its lifetime is tied to the scope, in which it has been created. Once the execution leaves this scope, a is destructed and memory is freed. All of that is taken care of, without you worrying about it at all.
Allocating a pointer does not equate to allocating an object. You need to use new and instantiate an object on the heap, or create the object on the stack:
A* a = new A();
// Or
A a;
A* aPntr = &a;
Pointer is not an object, it’s just a link that points somewhere. The reason to use them is that you can dynamically change what they’re pointing to.
A a;
A b;
A *pA;
{
bool condition;
// set condition here according to user input, a file or anything else...
if(condition)
pA = &a;
else
pA = &b;
}
Now I don’t have to take care about condition, it even doesn’t have to exist anymore and still I can profit from the choice made above.
pA->show();
Or I can use pointer to iterate over an array:
A array[10];
for(A* pA = array; pA < array+10; pA++)
{
pA->show();
}
(Note I used the original declaration of class A in both examples altough more meaningful it would be if each object of class A contained its specific information.)
There may not be one single reason for A *a; not to allocate an instance of A. It would be at odds with how C++ is designed. I would be somewhat surprised if Stroustrup considered it for long enough to identify a definitive reason not to do it.
A few different ways to look at it:
You didn't ask for an object of type A, so you don't get one. That's how C and C++ work.
A pointer object is an object that holds an address. You may as well ask why stationary manufacturers don't build a house when they manufacture an envelope, as ask why C++ doesn't allocate an object to be pointed at when you define a pointer.
There are many ways to allocate memory. Supposing that memory was going to be allocated, which one would you like? You could argue that in C++ new would be a sensible default for class types, but then it would probably be quite confusing either if char *c; called new char (because the behavior would be different from C) or if char *c; didn't allocate memory at all (because the behavior would be different from char *A;.
How and when would the memory be freed? If it's allocated with new then someone is going to have to call delete. It's much easier to keep things straight if each delete corresponds to a new, rather than each delete corresponding either to new or to defining a pointer with implicit memory allocation.
A pointer can be the location of an object, but it isn't always (sometimes it's null, sometimes it's off-the-end of an array). The object can be dynamically allocated but doesn't have to be. It would be very unhelpful of the language to make a pointer point to an object in cases where you don't need it. Therefore the language gives you the option not to allocate memory when defining a pointer. If you don't want that, then you should initialize the pointer with the result of a call to the memory-allocation mechanism of your choice.
You just create a pointer *a, but not allocate memory for it.
you should use A *a = new A();
I'm sorry to ask such a newbie question.
Here is my problem :
MyClass* c = new MyClass("test");
method(c);//error cannot convert MyClass* to MyClass
the definition :
method(MyClass c);
should I also define ?
method(MyClass* c);
I don't want to duplicate the code, what is the proper way ?
You're clearly a Java programmer! First of all, you will need to do:
MyClass* c = new MyClass("test");
Note that c is a "pointer to MyClass" - this is necessary because the new expression gives you a pointer to the dynamically allocated object.
Now, to pass this to a function that takes a MyClass argument, you will need to dereference the pointer. That is, you will do:
method(*c);
Note that because the function takes a MyClass by value (not a reference), the object will be copied into your function. The MyClass object inside method will be a copy of the object you allocated earlier. The type of the argument depends on exactly what you want your function to do and convey. If instead you want a reference to the object, so that modifying the object inside the function will modify the c object outside the function, you need your function to take a MyClass& argument - a reference to MyClass.
If you were to have the argument be of type MyClass*, then you could simply do:
method(c);
This will give you similar semantics to passing a reference, because the pointer c will be copied into the function but the object that pointer refers to will still be the dynamically allocated MyClass object. That is, if inside the function you modify *d, the object pointed to by c is also modified.
Passing a raw pointer like this is usually not a very good approach. The function will have to explicitly check that the pointer is not null, otherwise your program may crash under certain conditions. If you want pass-by-reference semantics, use reference types - it's what they're for.
However, you're better off not dynamically allocating your MyClass object in the first place. I guess you're only using new because you did it a lot in Java. In C++, the new expression is used to dynamically allocate an object. More often than not, you do not want to dynamically allocate an object. It is perfectly fine to create it with automatic storage duration, which you would do like so:
MyClass c("test");
method(c);
It is considered very good practise in C++ to avoid pointers and dynamic allocation unless you have a good reason. It will only lead you to more complicated code with more room for errors and bugs. In fact, the code you've given already has a problem because you didn't delete c;. When you do as I have just suggested, you don't need to explicitly delete anything, because the object will be destroyed when it goes out of scope.
MyClass *c = new MyClass("test");
method(*c);
it works if you defined a method like method(MyClass c)
But if you define you method like method(MyClass *c);
then it should be
MyClass *c = new MyClass("test");
method(c);
The two alternatives have consequences depending on what you want to do with the object you have created.
I have a class MyClassA. In its constructur, I am passing the pointer to instance of class B. I have some very basic questions related to this.
(1) First thing , is the following code correct? ( the code that makes a shallow copy and the code in methodA())
MyClassA::MyClassA(B *b){
this.b = b;
}
void MyClassA::methodA(){
int i;
i = b.getFooValue();
// Should I rather be using the arrow operator here??
// i = b->getFooValue()
}
(2) I am guessing I don't need to worry about deleting memory for MyClassA.b in the destructor ~MyClassA() as it is not allocated. Am I right?
thanks
Update: Thank you all for your answers! MyclassA is only interested in accessing the methods of class B. It is not taking ownership of B.
You need the arrow operator since b is a pointer.
Yes, unless the user of MyClassA expects to take the ownership of b. (You can't even be sure if b is a stack variable where delete-ing it will may the code crash.)
Why don't you use a smart pointer, or even simpler, a reference?
First thing , is the following code
correct? ( the code that makes a
shallow copy and the code in
methodA())
The answer depends upon who owns the responsibility of the B object's memory. If MyClassA is supposed just to store the pointer of A without holding the responsibility to delete it then it is fine. Otherwise, you need to do the deep copy.
I am guessing I don't need to worry
about deleting memory for MyClassA.b
in the destructor ~MyClassA() as it is
not allocated. Am I right?
Again depends on how memory for B is allocated. Is it allocated on stack or heap? If from stack then you need not explicitly free it in destructor of MyClassA, otherwise you need to to delete it.
1) . It depends on the life time of the pointer to B.
Make sure the when you call b->getFooValue(); b should be a valid pointer.
I will suggest use of initilization list and if you are only reading the value of the B object though it pointer then make it pointer to constant data.
MyClassA::MyClassA(const B *bObj) : b(bObj)
{}
2). As long as B is on the stack on need to delete it and if it is allocated to heap then it must be deleted by it the owner else you will have memory leak.
You can use smart pointer to get rid of the problem.
MyClassA::MyClassA(B *b){
this.b = b;
}
should be:
MyClassA::MyClassA(B *b){
this->b = b;
}
because this is treated as a pointer.
1)
this.b = b;
Here you pass a pointer to an instance of B. As Mac notes, this should be:
this->b = b;
b.getFooValue();
This should be b->getFooValue(), because MyClassA::b is a pointer to B.
2) This depends of how you define what MyClassA::b is. If you specify (in code comments) that MyClassA takes over ownership over the B instance passed in MyClassA's constructor, then you'll need to delete b in MyClassA's destructor. If you specify that it only keeps a reference to b, without taking over the ownership, then you don't have to.
PS. Regrettably, in your example there is no way to make ownership explicit other than in code documentation.