Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在不复制的情况下使用std::string?_C++_String_Stl_Parameter Passing_Pass By Reference - Fatal编程技术网

C++ 如何在不复制的情况下使用std::string?

C++ 如何在不复制的情况下使用std::string?,c++,string,stl,parameter-passing,pass-by-reference,C++,String,Stl,Parameter Passing,Pass By Reference,我有一个班级说 class Foo { public: void ProcessString(std::string &buffer) { // perform operations on std::string // call other functions within class // which use same std::string string } void

我有一个班级说

class Foo
{
   public:
      void ProcessString(std::string &buffer)
      {
          // perform operations on std::string

          // call other functions within class
          // which use same std::string string
      }

      void Bar(std::string &buffer)
      {
          // perform other operations on "std::string" buffer
      }

      void Baz(std::string &buffer)
      {
          // perform other operations on "std::string" buffer
      }
};
此类尝试使用
std::string
缓冲区在以下条件下使用各种方法对其执行操作:

  • 我不想传递我已经拥有的
    std::string
    的副本
  • 我不想创建这个类的多个对象
例如:

// Once an object is created
Foo myObject;

// We could pass many different std::string's to same method without copying
std::string s1, s2, s3;
myObject.ProcessString(s1);
myObject.ProcessString(s2);
myObject.ProcessString(s3);
我可以使用该字符串并将其指定为类成员,以便其他使用该字符串的函数可以了解它

但我们似乎无法拥有引用类成员
std::string&buffer
,因为它只能从构造函数初始化

我可以使用指向
std::string
的指针,即
std::string*buffer
并将其用作类成员,然后传递
s1、s2、s3的地址

class Foo
{
   public:
      void ProcessString(std::string *buf)
      {
          // Save pointer
          buffer = buf;

          // perform operations on std::string

          // call other functions within class
          // which use same std::string string
      }

      void Bar()
      {
          // perform other operations on "std::string" buffer
      }

      void Baz()
      {
          // perform other operations on "std::string" buffer
      }
   private:
       std::string *buffer;
};
或者,另一种方法是向每个函数传递对
std::string
缓冲区的引用,就像上面第一个示例中所示的

这两种方法似乎都有点难看,因为我很少看到将std::string用作指针或将类的所有函数传递给同一个参数,所以能够使用
std::string而不进行复制


有没有更好的办法,或者我现在做的很好?

因为你的要求是这样的

1.我不想传递我已经拥有的std::string的副本

2.我不想创建这个类的多个对象

使用pass by ref将是1的解决方案 使用static将是2的解决方案。因为它是一个静态memeber方法,所以该方法只有一个副本。不过,它不会属于任何物体。话虽如此,您可以直接调用此方法,而不是通过对象调用

比如说,

class Foo
{
      static void ProcessString(std::string &s)
      {
          // perform operations on std::string

          // call other functions within class
          // which use same std::string string
      }

}
当您调用此方法时,它将如下所示:

std::string s1, s2, s3;
Foo::ProcessString(s1);
Foo::ProcessString(s2);
Foo::ProcessString(s3);

更进一步,如果您只需要这个类的一个实例,您可以参考singleton设计模式。

您基本上需要回答这个问题:谁拥有这个字符串?
Foo
是否拥有该字符串?外部调用方是否拥有该字符串?或者他们都拥有这个字符串

“拥有”该字符串意味着该字符串的生存期与其绑定。因此,如果Foo拥有该字符串,那么当Foo停止存在或销毁该字符串时,该字符串将停止存在。共享所有权要复杂得多,但我们可以简单地说,只要任何所有者保留该字符串,该字符串就会存在

每种情况都有不同的答案:

  • Foo
    拥有该字符串:将该字符串复制到
    Foo
    ,然后让成员方法对其进行变异
  • 外部资源拥有该字符串:
    Foo
    不应在其自身堆栈之外保留对该字符串的引用,因为该字符串可能会在其不知情的情况下被销毁。这意味着它需要通过引用传递给每个使用它但不拥有它的方法,即使这些方法在同一个类中也是如此
  • 共享所有权:在创建字符串时使用
    Shared_ptr
    ,然后将该共享_ptr传递给共享所有权的每个实例。然后将共享的_ptr复制到一个成员变量,并由方法访问它。这比通过引用传递的开销要高得多,但如果您想要共享所有权,这是最安全的方法之一

  • 实际上,还有其他几种方法可以模拟所有权,但它们往往更为深奥。弱所有权、可转让所有权等。

    在MyObject中保留指向您的对象不拥有的字符串的引用或指针是危险的。很容易出现恶劣的未定义行为

    请看以下法律示例(酒吧是公共的):

    请看以下内容:

    if (is_today) {
        myObject.ProcessString(string("Hello"));  // uses an automatic temporary string
    }                                             // !! end of block: temporary is destroyed!
    else {
        string tmp = to_string(1234);            // create a block variable 
        myObject.ProcessString(tmp);             // call the main function 
    }                                            // !! end of block:  tmp is destroyed
    myObject.Bar();  // expects to work with pointer, but in reality use an object that was already destroyed !!  => UB                              
    
    这些错误非常严重,因为在读取函数的使用情况时,一切似乎都正常且管理良好。这个问题被自动销毁集团变量所隐藏

    因此,如果确实希望避免字符串的副本,可以按照设想使用指针,但只能在ProcessString()直接调用的函数中使用该指针,并将这些函数设为私有函数

    在所有其他情况下,我强烈建议重新考虑您的立场,并设想:

    • 应使用字符串的对象中字符串的本地副本
    • 或者在所有需要它的对象函数中使用
      字符串&
      参数。这避免了复制,但让调用方负责组织字符串的适当管理
    您已在未复制的情况下使用该字符串。您是通过引用传递的,即std::string&s。您可能不应该担心字符串复制太多。有什么问题吗?我不明白为什么不通过引用
    Bar
    Baz
    来传递字符串。@ChristianHackl问题主要在于性能,复制对象需要耗费大量CPU和内存,而且在调用者中无法修改对象[如果不完全替换它]除非你通过指针或引用传递。先生,我在noob ages中复制了足够多的字符串,知道它确实会导致性能下降,严重的问题取决于你处理字符串的强度。我知道我在这里谈论的是什么。我希望现在它更清楚。“如果你只想要这个类的一个实例,你可以参考单例设计模式。”如果你只想要这个类的一个实例,这里有一个更简单的模式:
    Foo f我甚至不认为需要类。为什么不仅仅是一个
    名称空间
    ?它可能出于任何原因,这超出了这个问题的范围。总之,代码满足用户的要求@AndreKostur@ChristianHackl不过,我不太清楚你在说什么。如果不使用singleton,这个类的多个实例是可能的。@STNYU:当然,我的评论很讽刺。你会发现现在单身往往被认为是一种反模式;真的
    if (is_today) {
        myObject.ProcessString(string("Hello"));  // uses an automatic temporary string
    }                                             // !! end of block: temporary is destroyed!
    else {
        string tmp = to_string(1234);            // create a block variable 
        myObject.ProcessString(tmp);             // call the main function 
    }                                            // !! end of block:  tmp is destroyed
    myObject.Bar();  // expects to work with pointer, but in reality use an object that was already destroyed !!  => UB