diff --git a/src/template.h b/src/template.h index f4650ad3..a3379e2d 100644 --- a/src/template.h +++ b/src/template.h @@ -215,10 +215,7 @@ inline std::unique_ptr strcopy(const std::unique_ptr &val, // std::string. It has c_str() and size() functions to mimic // std::string. It manages buffer by itself. Just like std::string, // c_str() returns NULL-terminated string, but NULL character may -// appear before the final terminal NULL. The crucial difference -// between this and std::string is that when ImmutableString is -// default constructed, c_str() returns nullptr, whereas std::string -// will return non nullptr. Both size() returns 0. +// appear before the final terminal NULL. class ImmutableString { public: using traits_type = std::char_traits; @@ -231,24 +228,30 @@ public: using const_pointer = const value_type *; using const_iterator = const_pointer; - ImmutableString() : len(0) {} + ImmutableString() : len(0), base("") {} ImmutableString(const char *s, size_t slen) - : len(slen), base(strcopy(s, len)) {} - ImmutableString(const char *s) : len(strlen(s)), base(strcopy(s, len)) {} + : len(slen), holder(strcopy(s, len)), base(holder.get()) {} + ImmutableString(const char *s) + : len(strlen(s)), holder(strcopy(s, len)), base(holder.get()) {} ImmutableString(std::unique_ptr s) - : len(strlen(s.get())), base(std::move(s)) {} + : len(strlen(s.get())), holder(std::move(s)), base(holder.get()) {} ImmutableString(std::unique_ptr s, size_t slen) - : len(slen), base(std::move(s)) {} - ImmutableString(const std::string &s) : len(s.size()), base(strcopy(s)) {} + : len(slen), holder(std::move(s)), base(holder.get()) {} + ImmutableString(const std::string &s) + : len(s.size()), holder(strcopy(s)), base(holder.get()) {} template ImmutableString(InputIt first, InputIt last) - : len(std::distance(first, last)), base(strcopy(first, last)) {} + : len(std::distance(first, last)), holder(strcopy(first, last)), + base(holder.get()) {} ImmutableString(const ImmutableString &other) - : len(other.len), base(strcopy(other.base, other.len)) {} + : len(other.len), holder(strcopy(other.holder, other.len)), + base(holder.get()) {} ImmutableString(ImmutableString &&other) noexcept : len(other.len), - base(std::move(other.base)) { + holder(std::move(other.holder)), + base(holder.get()) { other.len = 0; + other.base = ""; } ImmutableString &operator=(const ImmutableString &other) { @@ -256,7 +259,8 @@ public: return *this; } len = other.len; - base = strcopy(other.base, other.len); + holder = strcopy(other.holder, other.len); + base = holder.get(); return *this; } ImmutableString &operator=(ImmutableString &&other) noexcept { @@ -264,8 +268,10 @@ public: return *this; } len = other.len; - base = std::move(other.base); + holder = std::move(other.holder); + base = holder.get(); other.len = 0; + other.base = ""; return *this; } @@ -273,12 +279,13 @@ public: return ImmutableString(s, N - 1); } - const char *c_str() const { return base.get(); } + const char *c_str() const { return base; } size_type size() const { return len; } private: size_type len; - std::unique_ptr base; + std::unique_ptr holder; + const char *base; }; // StringRef is a reference to a string owned by something else. So diff --git a/src/template_test.cc b/src/template_test.cc index c4b7e672..8f7e8059 100644 --- a/src/template_test.cc +++ b/src/template_test.cc @@ -36,7 +36,7 @@ namespace nghttp2 { void test_template_immutable_string(void) { ImmutableString null; - CU_ASSERT(nullptr == null.c_str()); + CU_ASSERT("" == null); CU_ASSERT(0 == null.size()); ImmutableString from_cstr("alpha"); @@ -71,7 +71,7 @@ void test_template_immutable_string(void) { CU_ASSERT("charlie" == move); CU_ASSERT(7 == move.size()); - CU_ASSERT(nullptr == copy.c_str()); + CU_ASSERT("" == copy); CU_ASSERT(0 == copy.size()); // move assignment @@ -79,7 +79,7 @@ void test_template_immutable_string(void) { CU_ASSERT("alpha" == move); CU_ASSERT(5 == move.size()); - CU_ASSERT(nullptr == from_cstr.c_str()); + CU_ASSERT("" == from_cstr); CU_ASSERT(0 == from_cstr.size()); // from string literal