7

我习惯于在我的 C++ 应用程序中传递这样的字符串:

void foo(const std::string& input)
{
  std::cout << input.size() << std::endl;
}

void bar()
{
  foo("stackoverflow");
}

现在我有一个我希望字符串为 NULL 的情况:

void baz()
{
  foo("stackoverflow");
  foo(NULL); // very bad with foo implementation above
}

我可以foo改为:

void foo(const std::string* input)
{
  // TODO: support NULL input
  std::cout << input->size() << std::endl;
}

但是要传递字符串文字或将 a 复制char*到该实现,foo我需要编写如下内容:

void bar()
{
  string input("hi"); // annoying temporary
  foo(&input);
  foo(NULL);  // will work as long as foo handles NULL properly
}

我开始考虑继承std::string和添加一个null属性,但我不太确定这是一个好主意。也许const char*对可以为 NULL 的参数简单地使用字符串会更好,但是如果我想保存字符串(或 NULL)的副本而不必自己管理其内存怎么办?(请参阅使用 C 样式字符串有哪些缺点?等)

有什么聪明的解决方案吗?

4

7 回答 7

20

如果您希望类型为空,则将其设为指针。传递字符串指针而不是引用,因为这正是指针可以做的,而引用不能。引用总是指向同一个有效对象。指针可以设置为空,或重新定位以指向另一个对象。因此,如果您需要指针可以做的事情,请使用指针。

或者,使用 boost::optional,它允许以更类型安全的方式指定“此变量可能包含也可能不包含值”。

或者,当然,更改语义,以便您使用空字符串而不是 null,传递一个单独的 bool 参数来指定字符串是否可用,或者重构以便您一开始就不需要它。

于 2008-12-04T19:36:14.997 回答
11

函数重载来救援...

void foo( const std::string& input )
{
    std::cout << input << std::endl;

    // do more things ...
}

void foo( const char* input )
{
    if ( input != NULL ) foo( std::string(input) );
}

这将接受 c 样式的 char 数组和 std::strings,如果传入字符串文字或 char 数组,则会在堆栈上产生额外的开销,但允许您将实现保留在一个地方并保持良好的语法.

于 2008-12-04T19:44:15.573 回答
10

就个人而言,我会更改语义以传递空的 std::strings 而不是 NULL:

void foo(const std::string& input)
{
    if (!input.empty())
        std::cout << input.size() << std::endl;
}

void bar()
{
      foo("");
}
于 2008-12-04T19:33:00.433 回答
3

或者,混合前两个答案:

void fooImpl( const char* input )
{
    if ( input != NULL )
        std::cout << input << std::endl;
}

void foo( const std::string& input )
{
    fooImpl(input.c_str());    
}

void foo( const char* input )
{
    fooImpl(input);
}

相同的接口,堆栈上没有副本。如果您愿意,您也可以内联 fooImpl。

于 2008-12-04T20:11:18.857 回答
2

为什么不重载函数并且不给第二个重载参数呢?然后,两个重载都可以在内部调用一个提供读取逻辑的函数,并且该函数本身会传递一个指向std::string.

void foo_impl(string const* pstr) { … }

void foo(string const& str) {
    foo_impl(&str);
}

void foo() {
    foo_impl(0);
}
于 2008-12-04T19:37:11.487 回答
2

绝对不要继承自std::string. 继承是您在 C++ 中可以拥有的最紧密的耦合,并且您只是在寻找可空性,您可以简单地使用const char*、 重载或std::string *如果您真的想要的话。

于 2008-12-05T03:05:32.110 回答
1

如果你只是使用:

void foo(const char *xinput)
{
    if (xinput == NULL) {
        // do something exceptional with this
        return;
    }
    std::string input(xinput);
    // remainder of code as usual
}

是的,这确实会导致额外的分配和复制,并且调用该函数有点冗长,因为您需要.c_str()在通常情况下使用,但它确实为您提供了您想要的语义。

于 2008-12-04T19:28:31.487 回答