修改就地并返回副本是否有意义?

时间:2012-10-09 22:46:58

标签: c++ python mutable

注意:我正在标记这个Python和C ++,因为我在两者中都看到了一些例子,但这个问题与语言无关。

修改对象的函数或类方法有两个选择:直接在相关对象中修改数据,或者创建一个新副本并在保持原始状态不变的情况下返回它。通常,您可以通过查看函数返回的内容来判断哪个是哪个。

有时您会找到一个尝试同时执行这两项操作的函数,修改原始对象,然后返回该对象的副本或引用。有没有一种情况比只做一个或另一个提供任何优势?

我已经看到Fluent InterfaceMethod Chaining依赖于返回对象引用的示例,但这似乎是一个特殊情况,应该在上下文中显而易见。

我的第一个不好的例子直接来自Python documentation,并说明了可变默认参数的问题。对我来说,这个例子是不现实的:如果函数修改了它的参数,那么有一个默认值是没有意义的,如果它返回一个副本,那么应该在进行任何修改之前进行复制。这个问题只存在,因为它试图同时做到这两点。

def f(a, L=[]):
    L.append(a)
    return L

第二个示例来自CStringT::MakeUpper函数中的Microsoft C ++。文档说明了返回值:

  

返回字符串的副本,但全部为大写字符。

这导致人们期望原件保持不变。问题的一部分是文档具有误导性,如果您查看原型,您会发现它正在向字符串返回引用。除非仔细观察,否则您不会注意到这一点,并将结果分配给新字符串进行编译而没有错误。后来出人意料。

2 个答案:

答案 0 :(得分:4)

C ++示例Inc / Dec运算符

// Pre-Increment: Create a new object for return and modify self.
myiterator  operator++(int) {myiterator tmp(*this); operator++(); return tmp;}


// Post-Increment: modify self and return a reference
myiterator&  operator++() {/* Do Stuff*/ return *this;}

答案 1 :(得分:2)

在C ++中有一些明显的例子,你想要修改对象并返回一个引用:

  1. 分配:

    T & T::operator=(T && rhs)
    {
        ptr = rhs.ptr;
        rhs.ptr = nullptr;
        return *this;
    }
    

    这个修改了对象本身和参数,并返回对自身的引用。这样您就可以编写a = b = c;

  2. 输入输出流:

    std::ostream & operator<<(std::ostream & os, T const & t)
    {
        os << t->ptr;
        return os;
    }
    

    同样,这允许对操作进行链接,std::cout << t1 << t2 << t3;或典型的“提取和检查”if (std::cin >> n) { /* ... */ }

  3. 基本上,返回对其中一个输入对象的引用总是用于链调用或以某种形式评估结果状态,并且有几种有用的方案。

    另一方面,修改参数然后返回对象的副本似乎没那么有用。