How to use std :: string without copying?

I have a class let's say

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 } }; 

This class tries to use the std::string buffer to perform operations with it using various methods in these conditions:

  • I do not want to pass the copy of std::string that I already have.
  • I do not want to create multiple objects of this class.

For example:

 // Once an object is created Foo myObject; // We could pass many different std::string to same method without copying std::string s1, s2, s3; myObject.ProcessString(s1); myObject.ProcessString(s2); myObject.ProcessString(s3); 

I could use a string and assign it as a member of the class so that other functions can know about it.

But it seems that we cannot have a reference class std::string &buffer , because it can only be initialized from the constructor.

I could use a pointer to std::string ie std::string *buffer and use it as a member of the class, and then pass the addresses 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; }; 

Or another way can pass each function a link to the std::string buffer in the same way as shown in the first example above .

Both methods seem to be ugly workarounds, allowing you to use std::string without copying, since I rarely saw std :: string being used as a pointer or passing all the functions of a class to the same argument.

Is there any better in this, or what am I doing, just fine?

+7
c ++ string parameter-passing pass-by-reference stl
source share
3 answers

Saving a link or pointer to a string in MyObject that does not belong to your object is dangerous. It will be easy to get unpleasant undefined behavior .

Take a look at the following legal example (Bar is publicly available):

 myObject.ProcessString(s1); // start with s1 and keep its address myObject.Bar(); // works with s1 (using address previously stored) 

Look at the following UB:

 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 

Errors are very unpleasant, because when reading the use function, everything looks fine and is well managed. The problem is hidden by automatically destroying block variables.

So, if you really want to avoid copying the string, you can use the pointer as you expected, but you should only use this pointer in functions called directly by ProcessString () and make these functions private.

In all other cases, I strongly recommend that you reconsider your position and consider:

  • A local copy of the string in the object that should use it.
  • Or use string& parameters in the entire function of the object that needs it. This avoids copies, but reserves the responsibility to arrange proper string management.
+7
source share

You basically need to answer this question: who owns the string? Does Foo string? Does the external caller match the string? Or they both share ownership of the string.

Compliance with a string means that the lifetime of the string is tied to it. Therefore, if Foo owns a string, the string will cease to exist when Foo ceases to exist or destroy it. Co-ownership is much more complicated, but we can make it simpler by saying that the string will exist as long as one of its owners retains it.

In each situation, there is a different answer:

  • Foo owns the string: copy the string to Foo , then let the member methods mutate it.
  • An external resource owns a string: Foo should never contain a link to a string outside its own stack, since a string can be destroyed without its knowledge. This means that it must be passed by reference to each method that uses it and does not own it, even if the methods are in the same class.
  • Co-ownership: use shared_ptr when creating the string, and then pass this shared_ptr for each instance that owns the property. Then you copy shared_ptr to the member variable, and the methods access it. This has a much higher overhead and is then passed by reference, but if you want to get joint ownership, this is one of the safest ways to do this.

In fact, there are several other ways to model property, but they are usually more esoteric. Weak ownership, transferred property, etc.

+6
source share

Since your requirement is that

1. I do not want to pass a copy of std :: string, which I already have.

2.I do not want to create several objects of this class.

using pass by ref would be solution 1; using static will be solution 2. Since this is a static memeber method, there will be only one copy of this method. it will not belong to any object. In this case, you can call this method directly, and not through the object.

For example,

 class Foo { static void ProcessString(std::string &s) { // perform operations on std::string // call other functions within class // which use same std::string string } } 

when you call this method, it will be something like this:

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

One more step, if you want only one instance of this class, you can refer to the singleton design pattern.

0
source share

All Articles