The
std::basic_string
type uses the traits design pattern to handle
implementation details of the various string types, resulting in a
series of string-like classes with a common, underlying
implementation. Specifically, the
std::basic_string
class is paired with
std::char_traits
to create the
std::string
,
std::wstring
,
std::u16string
, and
std::u32string
classes. The
std::char_traits
class is explicitly specialized to provide policy-based implementation
details to the
std::basic_string
type. One such implementation detail is the
std::char_traits::length()
function, which is frequently used to determine the number of
characters in a null-terminated string. According to the C++ Standard,
[char.traits.require], Table 62 [ISO/IEC
14882-2014], passing a null pointer to this
function is undefined
behavior because it would result in dereferencing a null
pointer.
The following
std::basic_string
member functions result in a call to
std::char_traits::length()
:
basic_string::basic_string(const charT *, const Allocator &)
basic_string &basic_string::append(const charT *)
basic_string &basic_string::assign(const charT *)
basic_string &basic_string::insert(size_type, const charT *)
basic_string &basic_string::replace(size_type, size_type, const charT *)
basic_string &basic_string::replace(const_iterator, const_iterator, const charT *)
size_type basic_string::find(const charT *, size_type)
size_type basic_string::rfind(const charT *, size_type)
size_type basic_string::find_first_of(const charT *, size_type)
size_type basic_string::find_last_of(const charT *, size_type)
size_type basic_string::find_first_not_of(const charT *, size_type)
size_type basic_string::find_last_not_of(const charT *, size_type)
int basic_string::compare(const charT *)
int basic_string::compare(size_type, size_type, const charT *)
basic_string &basic_string::operator=(const charT *)
basic_string &basic_string::operator+=(const charT *)
The following
std::basic_string
nonmember functions result in a call to to
std::char_traits::length()
:
basic_string operator+(const charT *, const basic_string&)
basic_string operator+(const charT *, basic_string &&)
basic_string operator+(const basic_string &, const charT *)
basic_string operator+(basic_string &&, const charT *)
bool operator==(const charT *, const basic_string &)
bool operator==(const basic_string &, const charT *)
bool operator!=(const charT *, const basic_string &)
bool operator!=(const basic_string &, const charT *)
bool operator<(const charT *, const basic_string &)
bool operator<(const basic_string &, const charT *)
bool operator>(const charT *, const basic_string &)
bool operator>(const basic_string &, const charT *)
bool operator<=(const charT *, const basic_string &)
bool operator<=(const basic_string &, const charT *)
bool operator>=(const charT *, const basic_string &)
bool operator>=(const basic_string &, const charT *)
Do not call any of the preceding functions with a null pointer as
the
const charT *
argument.
This rule is a specific instance of EXP34-C. Do not dereference null pointers.
Implementation Details
Some standard library vendors, such as libstdc++,
throw a
std::logic_error
when a null pointer is used in the above function calls, though not
when calling
std::char_traits::length()
. However,
std::logic_error
is not a requirement of the C++ Standard, and some vendors
(e.g., libc++
and the Microsoft
Visual Studio STL) do not implement this behavior. For portability,
you should not rely on this behavior.
Noncompliant Code Example
In this noncompliant code example, a
std::string
object is created from the results of a call to
std::getenv()
. However, because
std::getenv()
returns a null pointer on failure, this code can lead to undefined
behavior when the environment variable does not exist (or some other
error occurs).
#include
<cstdlib>
#include <string>
void
f() {
std::string tmp(std::
getenv
(
"TMP"
));
if
(!tmp.empty()) {
// ...
}
}
|
Compliant Solution
In this compliant solution, the results from the call to
std::getenv()
are checked for null before the
std::string
object is constructed.
#include
<cstdlib>
#include <string>
void
f() {
const
char
*tmpPtrVal = std::
getenv
(
"TMP"
);
std::string tmp(tmpPtrVal ?
tmpPtrVal :
""
);
if
(!tmp.empty()) {
// ...
}
}
|