简体   繁体   中英

Why is there no std::string constructor for reference to array?

String literals are array objects:

typeid("hello").name()   // char [6]

This seems convenient because the size of the string literal (=array) is known at compile time. So why is there no constructor to std::string that takes a reference to an array?

// this would be great
template <int N>
std::string(const char (& array)[N]);

Instead there are constructors that take const char * s , const char * s, size_t n or two InputIterator s (eg. const char * begin, const char * end ). All of these have drawbacks; the array is implicitly converted to a pointer and the size information is lost, so various methods are used to get it back. Working, but increasingly crazy examples:

// std::string(const char * s) version:
std::string s1("hello");                      // calls std::strlen(s) internally

// std::string(const char * s, size_t n) version:
std::string s2("hello", 5);                   // programmer does std::strlen(s) mentally
std::string s3("hello", sizeof("hello"));     // have to repeat string literal

// macro helper to avoid repeating string literal (ugly and dangerous)
#define STRLIT(x) std::string(x, sizeof(x));  // could be a function I guess
std::string s4 = STRLIT("hello");             // not much improvement (and macros are evil)

// std::string(InputIterator begin, InputIterator end) version:
char tmp[] = "hello";                         // copy array
std::string s5(&tmp[0], &tmp[sizeof(tmp)]);   // so you can reference it twice

// or trust the compiler to return the same address for both literals
std::string s6(&"hello"[0], &"hello"[sizeof("hello")]);   // totally crazy

Such a templated constructor would be separately instantiated for each value of N . This could result in unnecessary code bloat.

The bloat is avoidable, but let's combine this thought with an answer from the ever-quotable Raymond Chen :

The answer to "Why doesn't this feature exist?" is usually "By default features don't exist. Somebody has to implement them."

The key question when considering whether there should be a constructor taking a char const (&)[N] (for some statically determined N ) is what the content of the resulting std::string should be. It might be obvious to some what it should be but I don't think it is. Consider this std::string("abc\\0def") :

  1. It could be a string with 8 elements, including the two null bytes.
  2. It could be a string with 7 elements, excluding the second null bytes.
  3. It could be a string with 3 elements, excluding everything starting at the first null byte.

If you use

std::cout << "string='" << "abc\0def" << "'\n";

you get the third option. It seems, this is the only sane alternative...

Because there is a generic constructor that uses iterators:

std::string s7(std::begin(container), std::end(container));

Note: assumes c++11 for std::begin/std::end but you can quickly write something similar really easyily.

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