如何从方法返回不可变参数,未更改,并且在c ++中没有副本?

时间:2015-03-13 06:24:05

标签: c++ immutability

如何从方法中返回参数,未更改,并且没有c ++中的副本?

// This is more or less the desired signature from the caller's 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;
    }
}

一个例子是C#的String.Trim方法。 C#字符串是不可变的,如果Trim不需要做任何工作,则返回对现有字符串的引用,否则返回带有修剪内容的新字符串对象。

如果接近上述方法签名,我将如何在C ++中模仿这种语义?

3 个答案:

答案 0 :(得分:2)

您的对象必须是此工作的引用类型。让我们举一个字符串的玩具示例:

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

答案 1 :(得分:1)

一个合理的选择是以支持这种方式的方式实现SomeImmutableObject - 内部作为指向逻辑状态的引用计数智能指针,而在外部它可以提供值语义。 (这可能会使线程代码的使用变得复杂 - 您可能希望阅读写时复制(COW)以及为什么它在实现std::string时变得不受欢迎。)

如果您仍然坚持使用现有的SomeImmutableObject实施,那么您无法进行更改,并且您无法使用引用计数的智能指针进行包装,然后选择获取有限的。

它不提供干净的来电者使用,但您可以使manipulationIsNeccessary成为来电者可访问的功能,然后让来电者使用新数据调用&#34;新对象&#34 ; 代码 - 在第二个函数中:

SomeImmutableObject obj;

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

通过让newObjectWithNewData成为一个单独的函数,你应该得到返回值优化(虽然它最好用你的编译器/设置检查)。

答案 2 :(得分:1)

你可能总是返回const SomeImmutableObject&amp;。请注意,将结果分配给对象将调用副本。

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

真正的诀窍是实施。当第一个&#34;如果&#34;子句有效,你可能会返回对临时变量的引用(不好的事情)。必须动态分配新创建的对象。

总而言之,我认为没有一些智能内存管理这是不可能的。