简体   繁体   中英

Why is there no warning or error when initializing a const pointer to null?

This might be a very basic question, but I tried to find the answer in SO and couldn't find the exact answer to it.

What's the point of initializing a const pointer with nullptr ?

int *const pi = nullptr;

Why does the compiler not emit a warning or error, seeing how pointer pi can't be used effectively anywhere in the program?

I have tried compiling this with g++ -w .

Also, Can you give some use case where a const pointer will get initialized to nullptr for a valid purpose in real code?

Do not confuse const , which means: "The values cannot change after initialization" with "this value is always, under all circumstances a nullptr ". What I mean is this:

 struct foo {
     int *const pi = nullptr;
     foo( int* p) : pi(p) {}
 };

Different instances of foo can have different values for pi .

Another way to have the initialization conditional is:

 int *const pi = (some_condition) ? nullptr : some_pointer;

Even with a plain

 int *const pi = nullptr;

there is nothing wrong. It is basically giving a different name to nullptr , so you can use pi anywhere where you can use a nullptr . For example as sentinel in a container:

 int * const empty = nullptr;
 for ( int* element : container) {
     if (element != empty) do_something(element);
 }

This might be considered obfuscation, and directly using nullptr would be more readable. Though consider the sentinel value changes later on, then using empty makes is simple to replace all occurences of it.

Although I agree that initializing a const pointer to nullptr isn't generally especially useful, one situation where it may me appropriate is where you would conditionally define the const pi pointer to either nullptr or some other (valid) address, depending on a compile-time setting, like in the following example. (The const qualifier prevents other code from inadvertently changing the value and, thusly, breaking the aforementioned compile-time condition.)

#include<iostream>  

#define USENULL 1 // Comment out this line to get a 'valid' pointer!

int main()
{
    int a = 42;
    #ifdef USENULL
    int* const pi = nullptr;
    #else
    int* const pi = &a;
    #endif
    int* pa = pi;
    if (pa) std::cout << *pa;
    else std::cout << "null pointer";
    std::cout << std::endl;
    return 0;
}

Such a situation could arise when you need to differentiate between debug and release builds, for example.

I'll try to generalize @AdrianMole's (second) example:

Sometimes, a piece of code is a degenerate case or an outlier case of a more general instruction or pattern. Thus:

  • In @AdrianMole's example, there is an out-of-source parameter which controls whether pi should have a meaningful value or not. You don't want to twist your source up too much in order to accommodate this scenario, so you keep the same code but use nullptr , likely with a later (run-time) check for whether you have a nullptr or not.

  • You might have a template class where the general definition is something like:

     template <typename T> class A { int *const pi = whatever<T>(); }

    with a specialization

    template <> class A<foo_t> { int *const pi = nullptr; }

    because you want to avoid calling whatever<foo>() .

It is likely that such code can be improved to avoid the explicit nullptr assignment. But it would be a bit excessive to push developers into doing this through a warning.

(An error is out of the question since it's perfectly valid code in terms of the language standard.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM