开发者

C++ Objects: When should I use pointer or reference

开发者 https://www.devze.com 2023-01-27 16:26 出处:网络
I can use an object as pointer to it, or its reference. I understand that the difference is that pointers have to be deleted manually, and references开发者_运维问答 remain until they are out of scope.

I can use an object as pointer to it, or its reference. I understand that the difference is that pointers have to be deleted manually, and references开发者_运维问答 remain until they are out of scope.

When should I use each of them? What is the practical difference?

Neither of these questions answered my doubts:

  • Pointer vs. Reference
  • C++ difference between reference, objects and pointers


A reference is basically a pointer with restrictions (has to be bound on creation, can't be rebound/null). If it makes sense for your code to use these restrictions, then using a reference instead of a pointer allows the compiler to warn you about accidentally violating them.

It's a lot like the const qualifier: the language could exist without it, it's just there as a bonus feature of sorts that makes it easier to develop safe code.


"pointers I have to delete and reference they remain until their scope finish."

No, that's completely wrong.

Objects which are allocated with new must be deleted[*]. Objects which are not allocated with new must not be deleted. It is possible to have a pointer to an object that was not allocated with new, and it is possible to have a reference to an object that was allocated with new.

A pointer or a reference is a way of accessing an object, but is not the object itself, and has no bearing on how the object was created. The conceptual difference is that a reference is a name for an object, and a pointer is an object containing the address of another object. The practical differences, how you choose which one to use, include the syntax of each, and the fact that references can't be null and can't be reseated.

[*] with delete. An array allocated with new[] must be deleted with delete[]. There are tools available that can help keep track of allocated resources and make these calls for you, called smart pointers, so it should be quite rare to explicitly make the call yourself, as opposed to just arranging for it to be done, but nevertheless it must be done.


suszterpatt already gave a good explanation. If you want a rule of thumb that is easy to remember, I would suggest the following:

If possible use references, use pointers only if you can not avoid them.

Even shorter: Prefer references over pointers.


Here's another answer (perhaps I should've edited the first one, but since it has a different focus, I thought it would be OK to have them separate).

When you create a pointer with new, the memory for it is reserved and it persists until you call delete on it - but the identifier's life span is still limited to the code block's end. If you create objects in a function and append them to an external list, the objects may remain safely in the memory after the function returns and you can still reference them without the identifier.

Here's a (simplified) example from Umbra, a C++ framework I'm developing. There's a list of modules (pointers to objects) stored in the engine. The engine can append an object to that list:

void UmbraEngine::addModule (UmbraModule * module) {
    modules.push(module);
    module->id = modules.size() - 1;
}

Retrieve one:

UmbraModule * UmbraEngine::getModule (int id) {
    for (UmbraModule **it=modules.begin(); it != modules.end(); it++) {
        if ((*it)->id == id) return *it;
    }
}

Now, I can add and get modules without ever knowing their identifiers:

int main() {
    UmbraEngine e;
    for (int i = 0; i < 10; i++) {
        e.addModule(new UmbraModule());
    }
    UmbraModule * m = e.getModule(5); //OK
    cout << m << endl; //"0x127f10" or whatever
    for (int j = 0; k < 10; j++) {
        UmbraModule mm; //not a pointer
        e.addModule(&mm);
    }
    m = e.getModule(15);
    cout << m << endl; //{null}
}

The modules list persists throughout the entire duration of the program, I don't need to care about the modules' life span if they're instantiated with new :). So that's basically it - with pointers, you can have long-lived objects that don't ever need an identifier (or a name, if you will) in order to reference them :).

Another nice, but very simple example is this:

void getVal (int * a) {
    *a = 10;
}
int main() {
    int b;
    getVal(&b);
    return b;
}


You have many situations wherein a parameter does not exist or is invalid and this can depend on runtime semantics of the code. In such situations you can use a pointer and set it to NULL (0) to signal this state. Apart from this,

  • A pointer can be re-assigned to a new state. A reference cannot. This is desirable in some situations.
  • A pointer helps transfer owner-ship semantics. This is especially useful in multi-threaded environment if the parameter-state is used to execute in a separate thread and you do not usually poll till the thread has exited. Now the thread can delete it.


Erm... not exactly. It's the IDENTIFIER that has a scope. When you create an object using new, but its identifier's scope ends, you may end up with a memory leak (or not - depends on what you want to achieve) - the object is in the memory, but you have no means of referencing it anymore.

The difference is that a pointer is an address in memory, so if you have, say, this code:

int * a = new int;

a is a pointer. You can print it - and you'll get something like "0x0023F1" - it's just that: an address. It has no value (although some value is stored in the memory at that address).

int b = 10;

b is a variable with a value of 10. If you print it, you'll get 10.

Now, if you want a to point to b's address, you can do:

a = &b; //a points to b's address

or if you want the address pointed by a to have b's value:

*a = b; //value of b is assigned to the address pointed by a

Please compile this sample and comment/uncomment lines 13 and 14 to see the difference (note WHERE the identifiers point and to WHAT VALUE). I hope the output will be self-explanatory.

#include <iostream>

using namespace std;

int main()
{
    int * a = new int;
    int b = 10;
    cout << "address of a: " << a << endl;
    cout << "address of b: " << &b << endl;
    cout << "value of a: " << *a << endl;
    cout << "value of b: " << b << endl;
    a = &b; //comment/uncomment
    //*a = b; //comment/uncomment
    cout << "address of a: " << a << endl;
    cout << "address of b: " << &b << endl;
    cout << "value of a: " << *a << endl;
    cout << "value of b: " << b << endl;
}


Let's answer the last question first. Then the first question will make more sense.

Q: "What is the practical difference[ between a pointer and a reference]?"

A: A reference is just a local pseudonym for another variable. If you pass a parameter by reference, then that parameter is exactly the same variable as the one that was listed in the calling statement. However, internally there usually is no difference between a pointer and a reference. References provide "syntax sugar" by allowing you to reduce the amount of typing you have to do when all you really wanted was access to a single instance of a given variable.

Q: "When should I use each of em?"

A: That's going to be a matter of personal preference. Here's the basic rule I follow. If I'm going to need to manipulate a variable in another scope, and that variable is either an intrinsic type, a class that should be used like an intrinsic type (i.e. std::string, etc...), or a const class instance, then I pass by reference. Otherwise, I'll pass by pointer.


The thing is you cannot rebind a reference to another object. References are bound compile time and cannot be null or rebound. So pointers aren't redundant if your doubt was that :)


As my c++ teacher used to put it, pointers point to the memory location while references are aliases . Hence the main advantage is that they can be used in the same way as the object's name they refer to, but in a scope where the object is not available by passing it there.

While pointers can be redirected to some other location, references being like constant pointers, can't be redirected. So references cant be used for traversing arrays in a functions etc.

However a pointer being a separate entity takes up some memory, but the reference being the same as the referred object doesn't take any additional space. This is one of its advantages.

I have also read that the processing time for references are less,

as

int & i = b ;

i++ ; takes lesser time than

int * j = b ;

(*j) ++ ;

but I am yet to confirm this. If anyone can throw light on this claim it would be great.

Comments are welcome :)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号