代码之家  ›  专栏  ›  技术社区  ›  dicroce

我需要一些C++大师关于扩展STD::字符串的意见

  •  7
  • dicroce  · 技术社区  · 15 年前

    我一直希望在STL的字符串中有更多的功能。由于STL类型的子类化是不允许的,所以大多数情况下我都看到了这些类的推荐扩展方法只是编写将类型作为第一个参数的函数(而不是成员函数)。

    我从来没有对这个解决方案感到兴奋过。首先,不一定很明显所有这些方法都在代码中,其次,我只是不喜欢语法。我想用。当我调用方法时!

    不久前,我想到了以下几点:

    class StringBox
    {
    public:
       StringBox( std::string& storage ) :
           _storage( storage )
       {
       }
    
       // Methods I wish std::string had...
       void Format(); 
       void Split();
       double ToDouble(); 
       void Join(); // etc...
    
    private:
      StringBox();
    
      std::string& _storage;
    };
    

    注意,StringBox需要一个对std::string的引用来构造…这对它的使用提出了一些有趣的限制(我希望,这意味着它不会导致字符串类的扩散问题)。在我自己的代码中,我几乎总是用一个方法在堆栈上声明它,只是为了修改一个std::string。

    使用示例可能如下所示:

    string OperateOnString( float num, string a, string b )
    {
        string nameS;
        StringBox name( nameS );
    
        name.Format( "%f-%s-%s", num, a.c_str(), b.c_str() );
    
        return nameS;
    }
    

    我的问题是:StCuxCommunity社区的C++大师对STL扩展的方法有什么看法?

    7 回复  |  直到 12 年前
        1
  •  15
  •   anon    15 年前

    由于我们中的大多数“gurus”似乎倾向于使用可能包含在名称空间中的自由函数,所以我认为可以放心地说,您的解决方案将不受欢迎。恐怕我看不出它有一个单独的优势,而且这个类包含一个引用的事实是邀请它成为一个悬而未决的引用。

        2
  •  19
  •   Stack Overflow is garbage    15 年前

    我从来没有对这个解决方案感到兴奋过。首先,不一定很明显所有这些方法都在代码中,其次,我只是不喜欢语法。我想用。当我调用方法时!

    我想用 $!---& 当我调用方法时!处理好它。如果你要编写C++代码,那就坚持C++约定。一个非常重要的C++约定是在可能的时候更喜欢非成员函数。

    有一个原因,C++大师建议:

    它提高了封装性、可扩展性和重用性。( std::sort 可以使用所有迭代器对 因为 它不是任何单个迭代器或容器类的成员。不管你怎么扩展 std::string 不能 打破它,只要你坚持非成员函数。即使您没有访问或不允许修改类的源代码,您仍然可以通过定义非成员函数来扩展它)

    就个人而言,我在你的代码中看不到这一点。这不是很简单,更易读和更短吗?

    string OperateOnString( float num, string a, string b )
    {
        string nameS;
        Format(nameS, "%f-%s-%s", num, a.c_str(), b.c_str() );
        return nameS;
    }
    
    // or even better, if `Format` is made to return the string it creates, instead of taking it as a parameter
    string OperateOnString( float num, string a, string b )
    {
        return Format("%f-%s-%s", num, a.c_str(), b.c_str() );
    }
    

    入乡随俗。 尤其是 当罗马人有充分的理由去做他们所做的。尤其是当你 拥有 做这件事的方式实际上没有一个优势。它更容易出错,让阅读您的代码的人感到困惑,这是非惯用的,而且做同样的事情只需要更多的代码行。

    对于您的问题,很难找到扩展的非成员函数 string ,如果这是一个问题,请将它们放在命名空间中。这就是他们的目的。创建一个 namespace StringUtil 或者别的什么,把它们放在那里。

        3
  •  2
  •   Emile Cormier    15 年前

    我将添加一些尚未发布的内容。这个 Boost String Algorithms library 采用了自由模板函数的方法,它们提供的字符串算法对于任何看起来像字符串的东西都是非常有用的:std::string、char*、std::vector、迭代器对…你说出来!它们都整齐地放在boost::algorithm名称空间中(我经常使用 using namespace algo = boost::algorithm 使字符串操作代码更简洁)。

    因此,考虑为字符串扩展使用自由模板函数,并研究如何使它们“通用”的Boost字符串算法。

    有关安全的printf样式格式,请签出 Boost.Format .它可以输出到字符串和流。

    我也希望所有的东西都是成员函数,但现在我开始看到光明了。UML和DoXEGEN总是迫使我把函数放在类内,因为我被C++ +API=类层次结构的思想洗脑了。

        4
  •  1
  •   orip    15 年前

    如果字符串的作用域与 StringBox 您可以获得SegFaults:

    StringBox foo() {
      string s("abc");
      return StringBox(s);
    }
    

    至少通过声明赋值运算符和copy ctor private来防止对象复制:

    class StringBox {
      //...
      private:
        void operator=(const StringBox&);
        StringBox(const StringBox&);
    };
    

    编辑:关于API,为了防止意外,我会 串箱 拥有字符串的副本。我认为有两种方法可以做到这一点:

    1. 将字符串复制到成员(不是引用),稍后获取结果-也作为副本
    2. 通过引用计数智能指针访问字符串 std::tr1::shared_ptr boost:shared_ptr ,以防止额外复制
        5
  •  1
  •   Smoke    12 年前

    松散函数的问题在于它们是松散函数。

    我敢打赌,你们中的大多数人已经创建了一个STL已经提供的函数,因为你们根本不知道STL函数存在,或者它可以做你们想要完成的事情。

    这是一个相当严苛的设计,尤其是对于新用户。(STL也得到了新的添加,进一步增加了问题。)

    谷歌:C++到字符串

    提到多少结果:std::to_string

    我很可能会找到一些古老的C方法,或者一些自制的版本,就像我找到任何给定函数的STL版本一样。

    我更喜欢成员方法,因为您不必费力地找到它们,也不必担心查找旧的不推荐的版本等。(也就是说,string.somemethod,几乎可以保证是您应该使用的方法,它为您提供了谷歌所需要的具体功能。)


    C样式的扩展方法是一个很好的解决方案。

    1. 它们的功能很松散。
    2. 它们通过IntelliSense显示为成员函数。

    这应该让每个人都能随心所欲。

    它似乎可以在IDE中完成,而不需要任何语言更改。

    基本上,如果解释器对一个不存在的成员进行调用,它可以检查头文件是否匹配松散函数,并在将其传递给编译器之前动态地修复它。

    当它加载IntelliSense数据时,可以执行类似的操作。

    我不知道如何对现有函数进行这样的操作,不应该轻而易举地进行这样的大规模更改,但是对于使用新语法的新函数来说,这不应该是一个问题。

        namespace StringExt
        {
            std::string MyFunc(this std::string source);
        }
    

    它可以自己使用,也可以作为std::string的成员使用,并且IDE可以处理所有的咕哝工作。

    当然,这仍然会留下方法分布在不同的头段上的问题,这些问题可以用不同的方式解决。

    1. 一些扩展头:可以包含常用方法的字符串扩展。
    2. 隐马尔可夫模型。。。。

    这是一个更难解决的问题,而不会引发问题…

        6
  •  0
  •   Larry Watanabe    15 年前

    如果要扩展可用于对字符串执行操作的方法,我将通过创建一个类来扩展它,该类具有将标准字符串作为参数的静态方法。 这样,人们可以自由地使用您的实用程序,但不需要更改其函数的签名就可以使用新的类。

    这打破了面向对象的模型一点,但使代码更加健壮——也就是说,如果您更改了字符串类,那么它对其他代码的影响就不会太大。

    遵循建议的指导原则,它们存在的原因是:)

        7
  •  0
  •   Potatoswatter    15 年前

    最好的方法是使用模板化的自由函数。其次是私人继承 struct extended_str : private string 在C++0X中,这样做会更容易。 using 构造函数。私有继承太麻烦了,仅仅添加一些算法也太冒险了。你做的事对任何事都太冒险了。

    您刚刚引入了一个非常重要的数据结构来完成代码标点的更改。您必须手动创建并销毁每个框 string 您仍然需要区分您的方法和本地方法。你很快就会厌倦这个会议。