Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411430 Posts in 69363 Topics- by 58416 Members - Latest Member: JamesAGreen

April 20, 2024, 01:57:57 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Pointers and references
Pages: [1]
Print
Author Topic: Pointers and references  (Read 1830 times)
Tuba
Level 10
*****



View Profile WWW
« on: November 21, 2014, 10:08:33 AM »

So, I come from a pure C background and most times I've used C++ I handled it more like C with classes. I'm trying to properly use the language now and one thing I've never understood is when to use reference to variables and when to use just pointers ?

I've seen codes that use just one of the two, codes that mix them, there doesn't seem to be a standard for it.

So, what do you recomend? Is there any real difference in using a reference or a pointer or it's just "cosmetic"?
Logged

Gtoknu
Level 0
***


View Profile
« Reply #1 on: November 21, 2014, 10:29:27 AM »

Imagine references as pointers but safer. If you just need to change something passed as reference, then avoid pointers.

Code:
ERROR_CODE DoSomething(int x, int& output)
{
    if(isValid(x))
    {
        output = doBlablabla(x);
        return NO_ERROR;
    }
    else
    {
        return ERROR;
    }
}

Now if you need to return an allocated resource, deal with memory directly, and all that stuff, you know pointers are there.

Code:
MyClass& createResource()
{
     MyClass instance;
     instance.x = 10;
     return instance; //it's going to work, but instance will be deleted right here, and this will lead to errors when you try to use the returned value.
}
Code:
MyClass& createResource()
{
     MyClass* instance = new MyClass();
     instance->x = 10;
     return *instance; //Works, and will continue to exist after end of the scope, but how do the caller know that it was allocated and he has to delete it? DOn't do this.
    //also, to delete this, he would have to do `delete &value;` which is no-good.
}
Code:
MyClass* createResource()
{
     MyClass* instance = new MyClass();
     instance->x = 10;
     return instance; //A little better, works, and the caller may know that he has to delete it. But try to find other way to manage your resources, this is bad.
}
The Rule Of Thumb is: if you can use a reference, do it. It's safer.
When you need to deal with memory directly, or return a newly created resource, then you won't be able to return a reference, do it with pointers.



BTW: don't believe me, I'm not a C++ guru at all.
Logged

wut
Polly
Level 6
*



View Profile
« Reply #2 on: November 21, 2014, 10:31:05 AM »

Use pointers for members / arguments that can be null, otherwise use references ( which is a code-design decision ). It's mostly cosmetic though, the generated assembly is in most situations identical.
Logged
oahda
Level 10
*****



View Profile
« Reply #3 on: November 21, 2014, 11:08:50 AM »

Don't use pointers if you can avoid it is a simple guideline I tend to use. Pointers are fine, but usually unnecessary so there is no need to bring that extra potential of shooting oneself in the foot (or more importantly, if you're writing a library or working on a collaborative project, to help others shoot themselves).

Sometimes you'll have to use pointers but might be able to restrict them to point simply to data elsewhere that can't be defined at declaration but must be filled in later (which is not possible with references which must be defined right away), which may still be stack data rather than new allocations on the heap.

Sometimes you'll use pointers just because a library returns them to you, but in that case you're not always in charge of deleting them yourself, or you might at least do it in an abstracted way using a destroyer function.

Polymorphism works with references just as well as pointers, so that sort of stuff need not be a problem (and you could just take the adress of a normal variable using the & operator otherwise, so that's not a problem at all).

On the rare occasions that you do have to allocate new data on the heap and you're using C++11 you might want to look into smart pointers. But they're a hassle to work with, so even then I tend to stick to just declaring unique pointers and then passing the real object around as a reference rather than messing with the other types of smart pointers.

The only reason I know ATM for myself to use pure pointers and the new and delete operators is to put class instances in unions, which need not be a problem in C++11 which is less strict when it comes to unions, but I've had some trouble with that, so I've just gone about it doing it the old way for that one exception and deleting the data in the destructor of the owning object.
Logged

Columbo
Level 0
***


View Profile
« Reply #4 on: November 21, 2014, 12:18:54 PM »

One distinction is that by creating a function signature that takes a reference rather than a pointer, you are making it very clear to the caller that they're not supposed to pass in NULL.

One disadvantage of references is that you cannot use the 'restrict' keyword on them, and if you're very performance focused that can be a significant problem. If you don't know what the restrict keyword is for, then you probably needn't worry about it.
Logged

RandyGaul
Level 1
*

~~~


View Profile WWW
« Reply #5 on: November 21, 2014, 01:32:50 PM »

A lot of people say "references are more safe". That's just not true in practice and doesn't even make sense. There is absolutely no difference between pointers and references other than that references have some additional *semantic* rules.

So look up the rules that references add onto pointers and there you go.
Logged
Gtoknu
Level 0
***


View Profile
« Reply #6 on: November 21, 2014, 01:36:46 PM »

On the rare occasions that you do have to allocate new data on the heap and you're using C++11 you might want to look into smart pointers. But they're a hassle to work with, so even then I tend to stick to just declaring unique pointers and then passing the real object around as a reference rather than messing with the other types of smart pointers.

I've been told that smart pointers aren't that good for gamedev. Our memory cycle is a little different from most applications (that's why gamedevs don't get along with GC'd languages), and this kinda make shared pointers and unique pointers not very useful for us. Though, I know they have their place in some gamedev code.
Logged

wut
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #7 on: November 21, 2014, 04:06:51 PM »

One disadvantage of references is that you cannot use the 'restrict' keyword on them, and if you're very performance focused that can be a significant problem. If you don't know what the restrict keyword is for, then you probably needn't worry about it.

restrict is a C keyword, not C++, unless C++14 adopted it.

As for pointers/references, my general rule is to that pointers denote ownership, references do not.  That is, if I give a function something by pointer, that function now owns that thing and is responsible for managing it.  It I pass something by reference, it belongs to the caller and the function is just using it.

Of course, I prefer pass/return by value over both of these whenever I can get away with it.
Logged



What would John Carmack do?
1kW
Level 0
**


View Profile
« Reply #8 on: November 21, 2014, 05:34:51 PM »

I still don't assimilate why we should use pointers or references. Bring some more light here, please Huh?
Logged
RandyGaul
Level 1
*

~~~


View Profile WWW
« Reply #9 on: November 22, 2014, 12:59:48 AM »

I still don't assimilate why we should use pointers or references. Bring some more light here, please Huh?

Are you asking why either should be used at all? They are used to store addresses to locations in memory. If you meant whether to use one over the other, well this gets into opinion land.

The address that a pointer holds can be modified during run-time, a reference cannot. References have some additional rules. The real reason why references were originally created is because they use the '.' syntax instead of the '->' syntax. Arrow syntax is the most worthless part of C++, so references can be quite nice in this way.
Logged
Boreal
Level 6
*


Reinventing the wheel


View Profile
« Reply #10 on: November 22, 2014, 02:23:20 AM »

References work very well with the concept of RAII.  Since a reference cannot be "empty", you are forced to declare it after (or deeper) than the object it is referring to.  This makes it much harder to accidentally use an object after it has been destroyed.

But they are not a silver bullet when it comes to memory safety - you still have to be wary when referring to anything allocated on the heap, especially if that object is not owned by your code.  For example, a reference to an element of a vector may be invalidated as soon as you call push_back(), and so you should not keep these references around.

This is why Rust is such a safe language - ownership is codified, and if you don't own the rights to a piece of memory your ability to use (and potentially abuse) it is very restricted.


Of course, pointer hacking is sometimes a necessary evil, and perfectly safe if you know what is going on with the memory.  Here's a particularly nasty snippet I wrote that involves (among other things) a horrible, horrible cast from an immutable pointer to a mutable generic one and back again.  But I know the usage patterns and lifetime of my memory to a T, and so this seemingly unsafe code is quite safe.

Code:
// redefine print to use the log
lua_pushlightuserdata(g_vm, (void *)&log);
lua_pushcclosure(g_vm, [](lua_State *vm)->int {
    // retrieve the captured log pointer
    const Log *log = (const Log *)lua_topointer(vm, lua_upvalueindex(1));

    // print all arguments
    int n = lua_gettop(vm);
    for(int i = 1; i <= n; ++i) {
        log->writeNormal(lua_tostring(vm, i), false);
        if(i < n) {
            log->writeNormal("\t", false);
        }
    }
    log->writeNewline();

    return 0;
}, 1);
lua_setglobal(g_vm, "print");
« Last Edit: November 22, 2014, 02:32:19 AM by Boreal » Logged

"In software, the only numbers of significance are 0, 1, and N." - Josh Barczak

magma - Reconstructed Mantle API
Columbo
Level 0
***


View Profile
« Reply #11 on: November 22, 2014, 04:05:18 AM »

One disadvantage of references is that you cannot use the 'restrict' keyword on them, and if you're very performance focused that can be a significant problem. If you don't know what the restrict keyword is for, then you probably needn't worry about it.

restrict is a C keyword, not C++, unless C++14 adopted it.


Thanks, didn't realise that restrict wasn't standardised in C++. I think most compilers do have an equivalent though, including many consoles and up-to-date versions of Visual Studio, Clang and GCC.
Logged

Krux
Level 2
**



View Profile
« Reply #12 on: November 22, 2014, 10:42:59 AM »

On this topic everybody has it's own guidelines. Mine is, don't use raw pointer at all, if you can avoid it. Use references where it is possible. If you need pointers, use the smart ones (eg. std::unique_ptr). And don't use any operators like + ++ - -- [] on pointers. if you want to iterate, use range based for, if you need to access an array, use std::vector instead. Sometimes there is no way around pointers, but not very often.
Logged
oahda
Level 10
*****



View Profile
« Reply #13 on: November 22, 2014, 11:38:39 AM »

A lot of people say "references are more safe". That's just not true in practice and doesn't even make sense. There is absolutely no difference between pointers and references other than that references have some additional *semantic* rules.

So look up the rules that references add onto pointers and there you go.
I agree. Don't get me wrong. I suppose the memory leaks that people are so afraid of are less of a problem on modern systems, too.
Logged

Tuba
Level 10
*****



View Profile WWW
« Reply #14 on: November 22, 2014, 12:32:53 PM »

I guess pointers are safe as long as you know well what you are doing.

Just remember to free everything you allocate and you should be fine about memory leaks, I usually try to keep my code more or less "symmetrical". Problem really starts when you need to have a pointer to a pointer... and than a pointer to that pointer, and so on...
Logged

oahda
Level 10
*****



View Profile
« Reply #15 on: November 23, 2014, 02:13:58 AM »

anyway #1 reason to avoid pointers is the arrow syntax is ugly Gomez
Logged

anthnich
Level 1
*



View Profile WWW
« Reply #16 on: November 25, 2014, 08:39:46 AM »

Pointers are best used to maximize polymorphism and memory allocations & management. Pointers also make handling "outside of scope" variable/memory usage much easier.

The biggest caveat of pointers is that you have to understand and keep track what you are pointing to/allocating. A good way to help take the burden off is to use smart pointers.
Logged

Turnover @ Steam
oahda
Level 10
*****



View Profile
« Reply #17 on: November 26, 2014, 12:27:49 AM »

My current project uses a smart unique pointer for a main game object so that it's killed once the program ends – the rest is stored inside that object (it's a component-based system) and so everything else goes out of scope or is deallocated recursively in its destructor. There aren't many allocations or deallocations to think of at all in my system, and it's quite nice.

I mostly use pointers for the SDL struct objects since SDL is a C library, and for some other data returned from pointer-loving libraries that I use. But it's all hidden away in the framework part of the project, so the game part of it really doesn't need to use pointers at all. Component creation is centralised and abstracted.

I sometimes use pointers or references to grab direct handles to subcomponents in the parent's constructor and put them into member variables so that I don't have to access them through slower function calls in real time, but that's obviously not a matter of de/allocations to think of.
Logged

Rusk
Level 1
*


View Profile
« Reply #18 on: November 28, 2014, 01:05:45 PM »

Herb Sutter gave a talk recently about style guidelines for c++. There was a section with suggestions for when to use pointers and refs in function calls and noob as I am I thought it was pretty good.
 
Start at 51 minutes for the parameter passing stuff, or skip to 55:20 for a close view of the actual slide:

Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic