gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

C/C++ > Some questions about pass by reference

#169897 - brave_orakio - Tue Aug 11, 2009 4:27 am

Hi guys, I'm confused about this declaration:
Code:

const std::string& getCode() const { return _Code; }


Why use the & and the const? Wouldn't it be better to not use the & so as not to need the const? I have to admit that I 'm not too good at C++ advanced declarations. I'm more comfortable with standard C.
_________________
help me

#169900 - kusma - Tue Aug 11, 2009 9:05 am

A std::string needs to be copied if you don't pass a reference to it. The consts are to maintain const correctness, so that you don't end up modifying a const object by returning a non-const reference to a member that can then be changed.

#169902 - brave_orakio - Tue Aug 11, 2009 9:54 am

I see, thank you. But I have to wonder why use a reference in the first place. The code came from an application that isn't on an embedded device
_________________
help me

#169903 - keldon - Tue Aug 11, 2009 10:09 am

It's called avoiding premature pessimism. If the string is returned by value then each time the method is called, new memory will be allocated and the text will be copied. There is no benefit in creating a design that forces this to happen each time when all you want to do is read the text.

#169910 - brave_orakio - Thu Aug 13, 2009 2:59 am

Ok, then another question whats the point of this?
Code:

void getClass(class*& name) {//function process}

and
Code:

void getClass(class*& name) const {//function process}


Int the first, isn't it technically the same as

Code:

void getClass(class* name)

And in the second function why put the const there?
_________________
help me

#169911 - Miked0801 - Thu Aug 13, 2009 6:22 am

The second one makes sure that the function doesn't change anything at all with the class * (which is a little strange - pointers and references don't mix often.) It tells the compiler not to allow any member value changes nor allow non-const member functions.

#169912 - brave_orakio - Thu Aug 13, 2009 7:39 am

Heh, so do you guys see functions like these used often? The one with the mixed *&? If you do, why use it? C++ has a lot of weirdness to it, or maybe I'm just not used to it?
_________________
help me

#169913 - Dwedit - Thu Aug 13, 2009 12:55 pm

Stuff like *& you might see in functions dealing with linked lists which need the head pointer, because they might change it.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#169914 - sajiimori - Thu Aug 13, 2009 6:04 pm

If a coder on my team wrote *&, I'd tell them to change it and never do it again.

References should be used for two things:

- To transparently optimize pass/return by value (but use const references only!)
- To implement operator* and operator[]

In all other cases, use pointers or plain values.

Beginner C++ books often use references "just because". Don't do that -- it's horribly confusing. For instance, you can't recognize output parameters at the call site.

#169915 - vuurrobin - Thu Aug 13, 2009 10:13 pm

I use *& to deallocate memory using the pointer and then set the pointer to NULL. avoids pointers to invalid memory.

Code:
/**
    @brief a template function to deallocate raw memory.

    this function will deallocate memory and set the pointer to NULL, but it wont call destructors.

    @param oldMemPointer a referrence to a pointer to the previously allocated memory.
*/
template <typename T>
inline void deallocRawMemNoError(T*& oldMemPointer)//a referrence to a pointer (I hope)
{
    if(oldMemPointer != NULL)
    {
        free(oldMemPointer);
        oldMemPointer = NULL;
    }
}


sajiimori wrote:
- To implement operator* and operator[]

and operator= with all it friends (+=, *=, ect)

#169916 - sajiimori - Thu Aug 13, 2009 11:45 pm

That anti-pattern provides next to zero protection against real-world dangling pointers. It is a feeble band-aid for only the absolute simplest case: basic single ownership. Even for that simple case, all other copies of the pointer are left dangling, and it doesn't even begin to address memory leaks.

Speaking of which, don't do manual deletes, where "manual" means "anything that can be forgotten", such as "deallocRawMemNoError".

For basic single ownership, use boost::scoped_ptr. If you don't want to use Boost, roll your own scoped_ptr -- it's absolutely trivial. Choosing the right smart pointers eliminates memory leaks 100%, and dangling pointers 99% (in my experience in a team environment).

operator= doesn't need non-const references. It typically accepts its argument by const reference, but even that isn't strictly necessary -- it's just an optimization.

#170155 - brave_orakio - Fri Sep 04, 2009 4:45 am

heh, been busy here in the office. what about this?

Code:


Class* varName;



the above is a member of a class. in thew deconstructor i see this

Code:


if(varName)
{
    delete varName;
    varName = 0
}



I'm not sure what happens inside one of the libraries, but the delete makes me think that somewhere a new was used. When exactly do we use new? For C++, I have never understood when.
_________________
help me

#170164 - Miked0801 - Fri Sep 04, 2009 9:47 pm

New allocates dynamic memory. Without a new call on varName, that delete would either do 'bad things' if varName was not initialized somwhere to null in a constructor, or nothing at all do to the minimal protection of the if(null) check.

varName = 0 should warn like crazy about int to pointer conversions as well.

Now, when you wanted to actually create an instance of varName somewhere to use, you would need to new it first, otherwise again you are doing very bad things with either null or garbage. It will not exist until new'd because it is only a pointer to a class. Without the pointer, it would be instantiated as soon as the containing class was created.

Hope that helps.

#170168 - sajiimori - Sat Sep 05, 2009 4:36 am

Literal 0 will implicitly convert to all pointer types.

#170169 - Miked0801 - Sat Sep 05, 2009 5:32 am

And you learn something new every day :)

#170190 - brave_orakio - Mon Sep 07, 2009 2:37 am

I see. So new is very much like malloc() then. I do remember a thread here asking if its ok to free a new or to delete a malloc. Of course we all know that no is the answer.
_________________
help me

#170191 - elwing - Mon Sep 07, 2009 6:37 am

sajiimori wrote:
Literal 0 will implicitly convert to all pointer types.


just to emphasis this, here is the NULL definition I'm using from Visual studio 2005 for win32 binary...

Code:
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif


not sure if that mean that pointer = 0 will make some warning with the C compiler or not... but at least using a void* cast work without warning for sure

#170227 - keldon - Wed Sep 09, 2009 8:32 pm

brave_orakio wrote:
I see. So new is very much like malloc() then. I do remember a thread here asking if its ok to free a new or to delete a malloc. Of course we all know that no is the answer.


New will also make a call to the constructor, e.g.

Code:
class MyClass
{
public:
   MyClass( int a, int b ) { (void) a; (void) b; }; // N.b. the (void)a statement is required to compile since <a> and <b> are never used in the function.
};


void function( void )
{
   MyClass *ptr = new MyClass(10, 20);
   // Will call new, as well as the MyClass constructor
}


In regards to the ((void *)0), it would not work in C++ as void pointers require explicit casts to a class pointer. E.g.

Code:
void function( void )
{
   MyClass *ptr;
   ptr = (void *)0); // Will fail compilation, as an explicit cast is needed

   ptr = (MyClass*) ((void *)0); // will compile as it has an explicit ...
}

#170241 - brave_orakio - Fri Sep 11, 2009 2:59 am

I see. Malloc() only reserves memory while new actually calls the constructor to create initial values for members. So I guess delete calls the destructor as well.
_________________
help me

#170244 - vuurrobin - Fri Sep 11, 2009 8:14 am

brave_orakio wrote:
I see. Malloc() only reserves memory while new actually calls the constructor to create initial values for members. So I guess delete calls the destructor as well.


yes.

new and delete will also check for overloaded operator new and delete. but I don't think that many people uses that.
_________________
my blog:
http://vuurrobin.100webcustomers.com/

#170245 - Miked0801 - Fri Sep 11, 2009 2:39 pm

You'd be surprised...

#170249 - Drovor - Fri Sep 11, 2009 3:24 pm

I've found a new/delete overload immensely useful for my DS application for tracking memory usage. I found a memory leak with it too. :)

http://forum.gbadev.org/viewtopic.php?t=16528