【问题标题】:Are these overloads necessary?这些重载是必要的吗?
【发布时间】:2011-07-29 08:40:23
【问题描述】:

我必须编写一个库,其中包含一个带有两个字符串参数的函数:

void foo(const std::string& arg1, const std::string& arg2);

我的库将被一些不喜欢 C++ 并且只习惯const char* 的人使用。

为了满足他们的喜好,我改变了原型:

void foo(const char* arg1, const char* arg2);

并使我的第一个版本成为一个简单的内联调用:

inline void foo(const std::string& arg1, const std::string& arg2)
{
  foo(arg1.c_str(), arg2.c_str());
}

当然,多亏了std::string 构造函数,它与第一个版本的工作方式几乎相同。编写此重载只是避免在某人仅通过 const char* 的情况下实例化无用的 std::string

但现在我想知道:这种重载真的有必要还是只是过早的优化?

另外,我觉得这有点不完整:我还应该写 void foo(const char* arg1, const std::string& arg2)void foo(const std::string& arg1, const char* arg2) 重载吗?如果我有 3、4 或更多 (n) 参数怎么办?我应该写 2n 个重载吗?

简而言之,你有没有遇到过类似的情况?你做了什么选择,为什么?

谢谢。

【问题讨论】:

  • 通过提供这样的重载来鼓励使用const char* 字符串实际上可以被视为一种悲观的形式,当您考虑到适当的字符串类型有时可以提供的算法优势时。

标签: c++ overloading


【解决方案1】:

IMO 有两个重载来处理组织内共存的两种不同编程风格是合理的。

从技术上讲,这只是一种优化:

  1. const char* 可以是 extern "C",因此可能对来自其他语言的绑定有用,甚至对于跨标准库实现不兼容的 dll 边界的其他 C++ 代码的绑定很有用。
  2. std::string 的转换可能会抛出bad_alloc,因此如果它不能以其他方式失败,那么const char* 版本如果您有一个C 风格的字符串并且想在nothrow 上下文中使用它会很有用。

还要注意,原则上c_str() 可以抛出bad_alloc,但我怀疑任何实现实际上都可以。

2n 重载对我来说似乎不值得 - 如果有人混合 stringchar* 那么这不仅仅是编程风格的差异,他们实际上是在使用混合格式原因。由于他们已经在使用两者,他们可以自己转换。

这一切都假设函数足够简单,您很乐意使用const char* 参数实现实际工作。如果基于string 的实现会更简单(例如,如果需要大量代码以使其异常安全),那么无论如何这可能会赢得效率,所以不要提供任何重载,让他们的const char*转换为string

【讨论】:

    【解决方案2】:

    只要你想使用 C++(而不是 C),第二个似乎是不必要的,如果你有这个:

    void foo(const std::string& arg1, const std::string& arg2);
    

    您可以将std::stringchar* 的所有组合称为:

    char *ca, *cb;
    std::string sa, sb;
    //...
    foo(ca,cb); //char*, char*
    foo(sa,cb); //std:string, char*
    foo(sa,sb); //std::string, std::string
    foo(ca,sb); //char*, std::string
    

    【讨论】:

    • 当然可以。但它对性能有影响吗?毕竟,实例化一个std::string 只是为了在函数体中调用c_str() 似乎没用。我不应该处理这个问题吗?
    • @iammilind:这证明了什么?如果您使用 未初始化 变量,那么在这两种情况下它的行为都是未定义的。在std::string 的情况下出现运行时错误很好,但是(不幸的是)在char* 的情况下你没有收到任何错误但它的UB:ideone.com/Ki6Ex
    • @ereOn:我会说不是,调用者应该处理这个问题。如果他们关心性能,他们可以观察到他们对const char*string 的调用会导致不必要的转换,而且修复很简单——在他们的第二个参数上调用c_str
    • 我知道这是一种不好的行为。但是对于const char* 的情况,我们可以进行空检查。看到这个例子是关于初始化指针的:ideone.com/02PTL
    【解决方案3】:

    如果const char * text 永远不会为空,你可以使用string,因为它有隐式构造函数,所以string 类版本就足够了。另一方面:如果const char * text 可以为空,则会产生运行时错误。

    还有一件事:在 DLL 接口上,STL 并不是很好的选择。所以如果函数是 DLL 接口的一部分,你可以使用 C 风格的字符串。

    我可以这样做:

    #include <string>
    using namespace std;
    
    void foo( const string arg0, const string arg1 )
    extern "C" _declspec( dllexport ) void foo( const char * arg0, const char * arg1 )
    {
      string string_arg0, string_arg1;
      if ( arg0 != 0 )
        string_arg0 = arg0;
      if ( arg1 != 0 )
        string_arg1 = arg1;
      foo(string_arg0, string_arg1);
    }
    

    【讨论】:

      【解决方案4】:

      在这种情况下,您可能只使用 (const char*,const char*) 并要求所有使用 std::string 的人使用 c_str()。这样就不会有任何内存分配开销,只有人们必须编写的额外 c_str() 。

      【讨论】:

        【解决方案5】:

        我的库将被一些不喜欢 C++ 和 仅用于 const char*。

        告诉他们做好准备并学习他们的编译器编译的语言。你选择std::string,因为这就是在 C++ 中的做法,如果他们不喜欢它,那么他们可以得到一个 C 编译器。

        【讨论】:

        • 我真的会这么说。但是这样做会让我在整个部门都被讨厌。所以不是一个真正的选择;)
        • @ereOn,还要确保他们不知道您是“ereOn”别名背后的人。 :)
        【解决方案6】:

        我认为你目前的做法是正确的。您在哪里为const char* 重载并提供一个也为std::string 服务的包装器。

        如果您的同事打算使用 C 风格的字符指针,那么最好这样做(现在的方式)。见以下案例;

        char *p = 0;
        foo(p);
        
        void foo (const string &s)
        {  // runtime error
        }
        

        Demo。如您所见,字符指针可能并不总是与std::string 配合得很好;所以为什么要冒险。即使人们可能不会进行这样的编码;您仍然应该避免这种潜在的危害,以实现长期可维护性。

        在函数内部,您始终可以从const char* 中选择std::string 并编写您的算法。

        【讨论】:

        • 很有可能,std::string 构造函数失败的情况也会导致底层函数失败。在剩下的情况下你很幸运并且不会出错,也许你只是比其他情况更早地发现了一个错误。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-27
        相关资源
        最近更新 更多