如何最好地定义/构造/初始化 std::string 包装类

non*_*741 2 c++ string wrapper

我在 std::string 周围使用了一个包装类,但是初始化/构造它的最简单/最干净/最完整的方法是什么。我需要至少 3 种方式

  • 从字符串文字
  • 从 std::string 右值,避免复制!?
  • 来自 string_view 和 string(是的,复制)

天真的程序员只想将任何构造自动委托给 std::string,但这不是一个特性。

struct SimpleString
{
    SimpleString() = default;
    
    template<typename T>
    SimpleString( T t ) : Text( t ) { }   // <==== experimental
    
    // Alternative: are these OK
    SimpleString( const char* text ) : Text( text ) { }
    SimpleString( std::string&& text ) : Text( text ) { }
    SimpleString( const std::string_view text ) : Text( text ) { }

    std::string Text;
};
Run Code Online (Sandbox Code Playgroud)

抢先注:是的,我想要它,我需要它。用例:调用通用函数,其中 SimpleString 的处理方式与 std::string 不同。

关于从 std::string 继承的注意事项:可能是一个坏主意,因为隐式转换将在第一时间发生。

Hum*_*ler 6

如果您的主要目标是字符串转换构造函数,则您不需要经历任何巨大的麻烦。最简单和最好的方法是只接受std::stringAPI 上的按值并将std::move其设置到位。

class SimpleString
{
public:
    SimpleString() = default;
    SimpleString(std::string text) : Text(std::move(text)) { }
    // ... other constructors / assignment ...

private:
    std::string Text;
};
Run Code Online (Sandbox Code Playgroud)

这样做,我们可以利用std::string已经可以构建的事实:

  • C 字符串/文字,
  • std::string_view,
  • 其他std::string对象(左值或右值),以及
  • 任何可能已经可以转换为的用户定义类型 std::string

这样做还使用户可以选择现在决定是SimpleString通过移动当前std::string对象来构建,还是允许SimpleString显式复制它。这为调用者提供了更大的灵活性。

这很有效,因为std::string无论如何您已经将拥有它,因此按值接受它并std::moveing 对象是一种“坐下”该值的简单方法。移动 astd::string相当便宜,相当于为指针、大小和分配器进行了一些分配——因此这产生的性能开销可以忽略不计,同时也是一种简单且可维护的方法。


现代 C++ 和移动语义使接受这些类型变得如此容易。您绝对可以重载所有 N 种构造它的方法(const char*, std::string_view, Ts 可转换为字符串等);但直接接受类型并移动它会简单得多。这是最灵活的方法,同时也保持简单和可维护。


以下是使用模板与使用std::string+进行比较的一些基准std::move。一般来说,保持简单更有利。你的同事和未来的维护者会感谢你(即使未来的维护者是你,一年后)。