How to return an immutable parameter from a method, without changes and without a copy in C ++?

How to return a parameter from a method, without changes and without a copy in C ++?

// This is more or less the desired signature from the caller point of view SomeImmutableObject ManipulateIfNecessary(SomeImmutableObject const& existingObject) { // Do some work… // ... if (manipulationIsNeccessary) { // Return a new object with new data etc (preferably without another copy)... return SomeImmutableObject(...); } else { // Return the original object intact (but with no further copies!)... return existingObject; } } 

An example is the C # String.Trim method. C # strings are immutable, and if Trim does not need to do any work, a link to the existing string is returned, otherwise a new string object with trimmed content is returned.

How would I simulate this semantics in C ++, given something close to the above method signature?

+6
source share
3 answers

For this, your object must be a reference type. Let us give an example of toys for strings:

 class RefString { public: RefString() : ref(new std::string()) { } RefString(const std::string& str) : ref(new std::string(str)) { } RefString trim_trailing_newline() { if (ref->back() == '\n') { return RefString(ref->substr(0, ref->size()-1)); } return *this; } size_t size() { return ref->size(); } private: std::shared_ptr<std::string> ref; }; int main(int argc, char** argv) { RefString s("test\n"); std::cout << s.size() << "\n"; std::cout << s.trim_trailing_newline().size() << "\n"; return 0; } 
+2
source

A reasonable option is to implement SomeImmutableObject in a way that supports this - internally, like a smart pointer to a logical state read with reference, and externally it can provide semantics of values. (This can make it harder to use from streaming code β€” you might want to read on copy-on-write (COW) and why it has become unpopular with the implementation of std::string .)

If you are stuck in an existing SomeImmutableObject implementation that you cannot change, and you cannot wrap it with a socket pointer with a list of links, then the choice will be limited.

It does not provide as pure use of the caller, but you can make manipulationIsNeccessary function available for calling, and then call the calling call with the code "new object with new data" in the second function:

 SomeImmutableObject obj; const SomeImmutableObject& o = manipulationIsNecessary(obj) ? newObjectWithNewData(obj) : obj; ...use o... 

Having a newObjectWithNewData separate function, you should get optimized return value (although it is always better to check with your compiler / settings).

+1
source

You can always return const SomeImmutableObject &. Note that when assigning a result to an object, a copy will be called.

 SomeImmutableObject x = ManipulateIfNecessary(y); // will invoke a copy-ctor 

The real trick is implementation. When the first β€œif” clause has an effect, you are likely to return a link to a temporary variable (which is bad to do). The created object must be dynamically allocated.

In general, I do not think this is easily possible without managing intellectual memory.

+1
source

Source: https://habr.com/ru/post/983730/


All Articles