capture clause (Also known as the lambda-introducer in the C++ specification.)
parameter list Optional. (Also known as the lambda declarator)
mutable specification Optional.
exception-specification Optional.
trailing-return-type Optional.
lambda body.
A lambda can introduce new variables in its body (in C++14), and it can also access, or capture, variables from the surrounding scope. A lambda begins with the capture clause (lambda-introducer in the Standard syntax), which specifies which variables are captured, and whether the capture is by value or by reference. Variables that have the ampersand (&
) prefix are accessed by reference and variables that do not have it are accessed by value.
An empty capture clause, [ ]
, indicates that the body of the lambda expression accesses no variables in the enclosing scope.
&
operatorA pointer however, is a variable that stores the memory address as its value.
A pointer variable points to a data type (like int
or string
) of the same type, and is created with the *
operator. The address of the variable you're working with is assigned to the pointer:
by using the *
operator (the dereference operator):
Note that the *
sign can be confusing here, as it does two different things in our code:
- When used in declaration (string* ptr), it creates a pointer variable.
- When not used in declaration, it act as a dereference operator.
// Reference: Output the memory address of food with the pointer (0x6dfed4)
cout << ptr << "\n";
// Dereference: Output the value of food with the pointer (Pizza)
cout << *ptr << "\n";
*ptr = "Hamburger";
|
|
The values contained in each variable after the execution of this are shown in the following diagram:
First, we have assigned the value
25
to myvar
(a variable whose address in memory we assumed to be 1776
).The second statement assigns
foo
the address of myvar
, which we have assumed to be 1776
.It is important to clearly differentiate that
foo
refers to the value 1776
, while *foo
(with an asterisk *
preceding the identifier) refers to the value stored at address 1776
, which in this case is 25
. Notice the difference of including or not including the dereference operator (I have added an explanatory comment of how each of these two expressions could be read):
|
|
Pointers and arrays
The concept of arrays is related to that of pointers. In fact, arrays work very much like pointers to their first elements, and, actually, an array can always be implicitly converted to the pointer of the proper type. For example, consider these two declarations:
|
|
The following assignment operation would be valid:
|
|
After that,
mypointer
and myarray
would be equivalent and would have very similar properties. The main difference being that mypointer
can be assigned a different address, whereas myarray
can never be assigned anything, and will always represent the same block of 20 elements of type int
.
|
|
|
A typical -but not so simple- statement involving these operators is:
|
|
Because
++
has a higher precedence than *
, both p
and q
are incremented, but because both increment operators (++
) are used as postfix and not prefix, the value assigned to *p
is *q
before both p
and q
are incremented. And then both are incremented. It would be roughly equivalent to:
|
|
int&& a means "a" is an r-value reference. && is normally only used to declare a parameter of a function. And it only takes an r-value expression.
Simply put, an r-value is a value that doesn't have a memory address. E.g. the number 6, and character 'v' are both r-values. int a, a is an l-value, however (a+2) is an r-value.
void foo(int&& a) { //Some magical code... } int main() { int b; foo(b); //Error. An rValue reference cannot be pointed to a lValue. foo(5); //Compiles with no error. foo(b+3); //Compiles with no error. int&& c = b; //Error. An rValue reference cannot be pointed to a lValue. int&& d = 5; //Compiles with no error. }
For example inserts to std::vector (or in fact any array creation) will not cost huge amount of allocs/copies anymore.
In C++ working with references become prevalent since they are safer alternative to pointers and very importantly new language features such as automatic call of constructors or destructors (automatic cleanup) or operators worked only with them.
Pointers: A pointer is a variable that holds memory address of another variable. A pointer needs to be dereferenced with * operator to access the memory location it points to.
References : A reference variable is an alias, that is, another name for an already existing variable. A reference, like a pointer, is also implemented by storing the address of an object.
A reference can be thought of as a constant pointer (not to be confused with a pointer to a constant value!) with automatic indirection, i.e the compiler will apply the * operator for you.
int i = 3; // A pointer to variable i (or stores // address of i) int *ptr = &i; // A reference (or alias) for i. int &ref = i;
int &p; p=a; // it is incorrect as we should declare and initialize references at single step.
5. On the other hand, a reference cannot be re-assigned, and must be assigned at initialization.
6. Memory Address: A pointer has its own memory address and size on the stack whereas a reference shares the same memory address (with the original variable) but also takes up some space on the stack.
7. NULL value: Pointer can be assigned NULL directly, whereas reference cannot. The constraints associated with references (no NULL, no reassignment) ensure that the underlying operations do not run into exception situation.
8. Indirection: You can have pointers to pointers offering extra levels of indirection. Whereas references only offer one level of indirection.I.e,
In Pointers, int a = 10; int *p; int **q; //it is valid. p = &a; q = &p; Whereas in references, int &p = a; int &&q = p; //it is reference to reference, so it is an error.
9. Arithmetic operations: Various arithmetic operations can be performed on pointers whereas there is no such thing called Reference Arithmetic.(but you can take the address of an object pointed by a reference and do pointer arithmetics on it as in &obj + 5).)
- Use references
- In function parameters and return types.
- Use pointers:
- Use pointers if pointer arithmetic or passing NULL-pointer is needed. For example for arrays (Note that array access is implemented using pointer arithmetic).
- To implement data structures like linked list, tree, etc and their algorithms because to point different cell, we have to use the concept of pointers.
References are used to refer an existing variable in another name whereas pointers are used to store address of variable.
References cannot have a null value assigned but pointer can.
A reference variable can be referenced by pass by value whereas a pointer can be referenced but pass by reference.
A reference must be initialized on declaration while it is not necessary in case of pointer.
A reference shares the same memory address with the original variable but also takes up some space on the stack whereas a pointer has its own memory address and size on the stack.
Pointers and references are equivalent, except:
- A reference is a name constant for an address. You need to initialize the reference during declaration.
int & iRef; // Error: 'iRef' declared as reference but not initialized
Once a reference is established to a variable, you cannot change the reference to reference another variable. - To get the value pointed to by a pointer, you need to use the dereferencing operator
*
(e.g., ifpNumber
is aint
pointer,*pNumber
returns the value pointed to bypNumber
. It is called dereferencing or indirection). To assign an address of a variable into a pointer, you need to use the address-of operator&
(e.g.,pNumber = &number
).
On the other hand, referencing and dereferencing are done on the references implicitly. For example, ifrefNumber
is a reference (alias) to anotherint
variable,refNumber
returns the value of the variable. No explicit dereferencing operator*
should be used. Furthermore, to assign an address of a variable to a reference variable, no address-of operator&
is needed.
In C/C++, by default, arguments are passed into functions by value (except arrays which is treated as pointers). That is, a clone copy of the argument is made and passed into the function. Changes to the clone copy inside the function has no effect to the original argument in the caller. In other words, the called function has no access to the variables in the caller
Pass-by-Reference with Pointer Arguments
Pass-by-Reference with Reference Arguments
Instead of passing pointers into function, you could also pass references into function, to avoid the clumsy syntax of referencing and dereferencing.
That is because a temporary can not bind to a non-const reference.
double &m = a;
a
is of type int
and is being converted to double
. So a temporary is created. Same is the case for user-defined types as well.
Foo &obj = Foo(); // You will see the same error message.
Just make it a constant: const Foo &obj = Foo();
The intuition here is that you cannot use a "mutable" reference because, if you did, you'd be able to modify some object that is about to disappear, and that would be dangerous. Notice, by the way, that holding on to a const reference to a temporary object ensures that the temporary object isn't immediately destructed. This is a nice guarantee of C++, but it is still a temporary object, so you don't want to modify it.
In C++11, however, there's a new kind of reference, an "rvalue reference", that will let you bind a mutable reference to an rvalue, but not an lvalue. In other words, rvalue references are perfect for detecting if a value is temporary object or not. Rvalue references use the && syntax instead of just &, and can be const and non-const, just like lvalue references, although you'll rarely see a const rvalue reference (as we'll see, mutable references are kind of the point):
1 2 | const string&& name = getName(); // ok string&& name = getName(); // also ok - praise be! |
auto
keyword declares a variable whose type is deduced from the initialization expression in its declarationThe macro NULL
is an implementation-defined null pointer constant, which may be
an integral constant expression rvalue of integer type that evaluates to zero | (until C++11) |
an integer literal with value zero, or a prvalue of type std::nullptr_t |
- De-allocation of memory
int
main()
{
int
*ptr = (
int
*)
malloc
(
sizeof
(
int
));
// After below free call, ptr becomes a
// dangling pointer
free
(ptr);
// No more a dangling pointer
ptr = NULL;
}
// The pointer pointing to local variable becomes // dangling when local variable is static. #include<stdio.h> int *fun() { // x is local variable and goes out of // scope after an execution of fun() is // over. int x = 5; return &x; } |
A garbage Address
// The pointer pointing to local variable doesn't // become dangling when local variable is static. #include<stdio.h> int *fun() { // x now has scope throughout the program static int x = 5; return &x; } |
void main() { int *ptr; ..... ..... { int ch; ptr = &ch; } ..... // Here ptr is dangling pointer }
Important Points
- void pointers cannot be dereferenced. It can however be done using typecasting the void pointer
- Pointer arithmetic is not possible on pointers of void due to lack of concrete value and thus size.
int
main()
{
int
x = 4;
float
y = 5.5;
//A void pointer
void
*ptr;
ptr = &x;
// (int*)ptr - does type casting of void
// *((int*)ptr) dereferences the typecasted
// void pointer variable.
printf
(
"Integer variable is = %d"
, *( (
int
*) ptr) );
// void pointer is now float
ptr = &y;
printf
(
"\nFloat variable is= %f"
, *( (
float
*) ptr) );
return
0;
}
#include <stdio.h> int main() { // Null Pointer int *ptr = NULL; printf ( "The value of ptr is %u" , ptr); return 0; }
|
std::ios::sync_with_stdio(false);
- Like with all things, there is a caveat here. With synchronization turned off, using cin and scanf() together will result in an undefined mess.
- With synchronization turned off, the above results indicate that cin is 8-10% faster than scanf(). This is probably because scanf() interprets the format arguments at runtime and makes use of variable number of arguments, whereas cin does this at compile time.
cout << endl : Inserts a new line and flushes the stream cout << "\n" : Only inserts a new line.