简体   繁体   中英

How `const std::string& s = nullptr` works as an optional parameter

To my knowledge a reference cannot be null, but when I run code like this:

#include <iostream>
#include <string>

void test(int i, const std::string& s = nullptr) {
  std::cout << i << " " << s << std::endl;
}

int main() {
  test(1, "test");
  test(2);
}

the optional parameter s can be null, and the code is built. What's more, when test(2) runs, the program throws exceptions instead of printing some random strings.

When I changed s to some basic type like int, it failed to compile, so I think the magic stays inside the string class, but how?

And what's more, how can I check if s is null or not? if I using if(s==nullptr) or if(s.empty()) , it fails to compile.

test initialized its argument by using constructor number 5 of std::basic_string<char> :

basic_string( const CharT* s,
              const Allocator& alloc = Allocator() );

Since it needs to materialize a temporary ( std::string ) to bind to that reference. That is because a reference must be bound to an object of a correct type, which std::nullptr_t isn't. And said constructor has a not null constraint on the pointer being passed. Calling test without an explicit argument leads to undefined behavior.

To be perfectly clear, there is no such thing as a null reference in a well-formed C++ program. A reference must be bound to a valid object . Trying to initialize one with nullptr will only seek out to do a conversion.

Since a std::string is an object with a well-defined "empty" state, a fixed version can simply pass in a default initialized string:

void test(int i, const std::string& s = {}); // Empty string by default.

Once the contract violation is fixed, s.empty() should give meaningful results again.

Reference indeed can not be null, however const std::string& s = nulltr does not do what you think it does. When second parameter is not specified compiler will create a string object invoking implicit string constructor that takes a pointer to null-terminated string as first parameter. So test(2); invocation looks like this:

test(2, ::std::string(static_cast<char const *>(nullptr), ::std::string::allocator_type()));

Note that passing nullptr as this first parameter causes Undefined Behavior.

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