Why to use a pointer..?

General base question, why to use pointers anyways

 
  My first post
In modern C++, you will very rarely use pointers. Instead, you will use things like std::unique_ptr.
http://www.cplusplus.com/doc/tutorial/pointers/

No, it does not directly say why, but knowing the properties of pointers is a prerequisite to enlightment.
> why to use pointers anyways

As far as possible, do not use pointers of any kind - either raw pointers or std::unique_ptr and the like.

At some time in the future, you will encounter a situation where you can't do without pointers. Till then write programs as if pointers do not exist.

Even after you have understood and used pointers in your code, the first rule continues to hold: as far as possible, do not use pointers of any kind.
Could you guys explain why pointers are bad?
Whether wrapped in std::unique_ptr, in some other structure, or not wrapped at all, pointers are necessary when you don't know at compile time how much data you will be dealing with. In this case, the program can ask for more memory at run time to hold extra data.

But how will the program refer to this extra data? The answer is a pointer.

Sounds great, so why are pointers bad? Well it turns out that you frequently need that extra memory for a short time and then you don't need it any more. In that case, you should release the memory so it can be reused.

In fact, it's very common for a program to run through this "allocate memory, use memory, release memory" many many times, so it's important that you release it.

The problem is that it's easy to mess up the code and forget to release the memory. In this case the program will use more and more memory until you run out. It's also easy to release memory before you're actually done using it, or to allocate N bytes of memory and actually use N+1 byes. In these cases there's a good chance that the program will fail.

Hope this helps,
Dave
At some point in the future of C++ we will (hopefully) have std::dynarray, which will mitigate the frequent dynamic allocations and deallocations for when we know the size at runtime and the size doesn't need to change for the duration of the container. But, that's for the future.
> std::dynarray, which will mitigate the frequent dynamic allocations and deallocations
> for when we know the size at runtime and the size doesn't need to change for the duration of the container.

If the size doesn't need to change for the duration of the container, std::maybe::dynarray would have the same performance characteristics as a std::vector with an initial call to reserve(): both would have just one allocation and one deallocation.

In many scenarios, even if the size doesn't need to change, std::vector<> would be a better option.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
    std::size_t N = 1024 * 8 ; // 8K

    std::maybe::dynarray<std::string> d(N) ; // allocate, default construct 8K strings
    // we can assign or move assign to them later

    std::vector<std::string> v; 
    v.reserve(N) ; // allocate
    // we can push_back() rvalues or directly construct in-situ with emplace() later

    // move assign to 2K strings in d
    // emplace 2K strings into v

    // ...
    // do something which results in an exception being thrown

    // stack unwind
    // destructor of v invoked: destroy 2K strings, deallocate
    // destructor of d invoked: destroy 8K strings, deallocate
}
> Could you guys explain why pointers are bad?

Pointers aren't bad per se; in fact they are extremely useful. But they are also just more difficult to deal with than values. The idea is that our code becomes easier to reason about if we do not have to directly deal with pointers; their use is encapsulated.

This is easy to write, easy to understand, and easy to modify. We are looking at things from a high level of abstraction:
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <string>

int main()
{
    std::cout << "please type in your first name: " ;
    std::string name ;
    std::cin >> name ;
    std::cout << "Hello " << name << '\n' ;
}


This program would not be feasible without a battery of pointers to back up the implementation.

std::cout internally holds a pointer to a stream buffer object.
It also has a locale object which in turn contains an associative array of reference-counted pointers to a dozen or so facet objects.

Some of these facets ...

std::string too uses pointers internally; std::cin >> name ; requires careful management of those pointers.

In contrast, this is code with equivalent functionality where we decide to deal with pointers (just the ones that std::string uses) ourselves. Brittle, error-prone code that is difficult to write and difficult to understand:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// adapted from 'Learning Standard C++ as a New Language' - Stroustrup
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

int main()
{
    size_t sz = 20 ;
    char* name = (char*)malloc(20) ;
    if( name == NULL ) return 1 ;

    puts( "please type in your first name: " ) ;

    int c ;
    while( ( c = getchar() ) != EOF )
    {
        if( !isspace(c) )
        {
            ungetc( c, stdin ) ;
            break ;
        }
    }

    size_t pos = 0 ;
    while( ( c = getchar() ) != EOF )
    {
        if( isspace(c) )
        {
            name[pos] = 0 ;
            break ;
        }

        name[pos] = c ;
        if( pos == sz-1 )
        {
            sz *= 2 ;
            char* temp = (char*)realloc( name, sz ) ;
            if( temp == NULL )
            {
               free(name) ;
               return 1 ;
            }
            else name = temp ;
        }
        ++pos ;
    }

    printf( "Hello %s\n", name ) ;
    free(name) ;
}

Notice how the simple logic of the program (ask for the first name, read it, print a hello message) is overwhelmed by low-level implementation details.
If the size doesn't need to change for the duration of the container, std::maybe::dynarray would have the same performance characteristics as a std::vector with an initial call to reserve()

Not always. The proposal attempts to let the compiler allocate the dynarray on the stack when practical, and this is more efficient than allocating on the heap.
> The proposal attempts to let the compiler allocate the dynarray on the stack when practical

The IS does not proscribe a standard-conforming allocator from allocating on the stack when practical (assuming that there is a stack and there is a heap; the standard does not require that an implementation must have either of these).

For instance, the standard library compatible allocator in chromium:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// This allocator can be used with STL containers to provide a stack buffer
// from which to allocate memory and overflows onto the heap. This stack buffer
// would be allocated on the stack and allows us to avoid heap operations in
// some situations.

// ....

  // Actually do the allocation. Use the stack buffer if nobody has used it yet
  // and the size requested fits. Otherwise, fall through to the standard
  // allocator.
  pointer allocate(size_type n, void* hint = 0) {
    if (source_ != NULL && !source_->used_stack_buffer_
        && n <= stack_capacity) {
      source_->used_stack_buffer_ = true;
      return source_->stack_buffer();
    } else {
      return std::allocator<T>::allocate(n, hint);
    }
  }


std::vector<> is an allocator-aware-container, the IS does not have to explicitly 'let' it allocate memory on the stack.
The use of an allocator in std::maybe::dynarray<> is optional.
Hello. There is a simple rule. Use references(&) when you need but pointers(*) when you must.
Last edited on
Topic archived. No new replies allowed.