开发者

C++ reference & const pointers in C/C++

开发者 https://www.devze.com 2023-01-26 06:58 出处:网络
Recently while I was explaining the basic difference between pointers and references(in context of C++ programming) to someone, I told the usual explanations which talk about different function argume

Recently while I was explaining the basic difference between pointers and references(in context of C++ programming) to someone, I told the usual explanations which talk about different function argument passing conventions - Call by value, Call by pointer, Call by reference, and all the associated theory about references.

But then I thought whatever a C+ reference does in terms of argument passing,(Allows a memory efficient way of passing large structures/objects, at same time keeps it safe by not allowing the callee to modify any variables of the object passed as reference, if our design demands it)

A const pointer in C would achieve the same thing , e.g. If one needs to pass a structure pointer say struct mystr *ptr, by casting the structure pointer as constant -

func(int,int,(const struct mystr*)(ptr));

will ptr not be some kind of equivalent to a reference?

  1. Will it not work in the way which would be memory efficient by not replicating the structure(pass by pointer) but also be safe by disallowing any changes to the structure fields owing to the fact that it is passed as a const pointer.

    In C++ object context, we may pass const object pointer instead of object reference开发者_如何学Go as achieve same functionality)

  2. If yes, then what use-case scenario in C++, needs references. Any specific benefits of references, and associated drawbacks?

thank you.

-AD


You can bind a const reference to an rvalue:

void foo(const std::string& s);

foo(std::string("hello"));

But it is impossible to pass the address of an rvalue:

void bar(const std::string* s);

bar(&std::string("hello"));   // error: & operator requires lvalue

References were introduced into the language to support operator overloading. You want to be able to say a - b, not &a - &b. (Note that the latter already has a meaning: pointer subtraction.)

References primarily support pass by reference, pointers primarily support reference semantics. Yes I know, the distinction isn't always quite clear in C++.


There are two typical use-case scenarios:

First: Pointers denote optional arguments. Since, references cannot be NULL, but pointers can, document in the coding style that any argument that is notated as pointer, may be NULL, the function needs to handle that. Optional arguments can then be const or non-const, as can mandatory (reference) arguments.

Second: References are only used in conjunction with the const keyword, because the calling syntax suggests to the reader pass-by-value semantics, which is by definition constant. Then pointers are only used for arguments that can be changed by the callee.

I personally prefer the first option, because there each of the four cases "const reference", "non-const reference", "const pointer", "non-const pointer" has a different meaning. Option two only differentiates between two "things": "function may modify that value" vs. "function will not modify that value".


In terms of the referent object, what code can manipulate given a const reference is the same as what it can do with a pointer to a const object, and similarly what it can manipulate given a non-const reference is the same as given a pointer to a non-const object.

What a reference prevents the called function from doing is changing which object the reference refers to, or pointer arithmetic on the reference.

In terms of the caller, a const reference can be bound directly to an rvalue, and you have well defined semantics when creating and destroying objects passed as arguments. This is a common idiom - to construct a temporary for an argument:

// declaration
void bar ( const Foo& );

// use
bar ( Foo() );

But it isn't immediately obvious that the Foo object in these has a lifespan which exceeds the length of the function call:

// declaration
void bar ( const Foo* );

// use
Foo temp;
bar ( &temp );

// cast to avoid warning about taking address of temporary 
bar ( &static_cast<const Foo&>( Foo() ) );  

// helper function to same effect 
template<typename T> const T* address_of ( const T& t) { return &t; }

bar ( address_of ( Foo() ) );

Though obviously the latter, being just a function call, should make it obvious it does.

Basically, the references are syntactic sugar for pointers which point to single objects, not the start of arrays.

0

精彩评论

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