C++:不可变方法版本

问题描述 投票:0回答:3

在 C++11 中,提供方法的两个版本的最佳方式是什么,一种用于修改对象本身,另一种则返回修改后的副本?

例如,考虑一个具有“append(string)”方法的字符串类。有时您可能希望使用追加来修改现有的字符串对象,有时您可能希望保持字符串对象相同并创建一个副本。

当然,我可以只实现第一个版本,并在每次需要时手动创建一个新对象,但这会向我的项目添加多个临时变量和代码行。

如果仍然不清楚我要做什么:

String s1("xy");
String s2 = s1.appendCopy("z");
s1.appendThis("w");
// s1 == "xyw"
// s2 == "xyz"

在 Ruby 中,有一个概念(或者更确切地说,命名约定),它表示此类方法有两种变体:append(创建新字符串)和append! (修改此对象)

C++ 没有这样的东西,所以我会被像“appendCopy”这样丑陋的方法名称所困扰。

有没有好的方法来实现我想做的事情?

到目前为止,我最好的想法是使修改版本类成员和复制/不可变版本静态方法,这些方法将对象作为 const 参数来处理。

c++ c++11
3个回答
8
投票

实际上有一个指导方针,由 Herb Sutter 在 GotW #84 中表达:

更喜欢非会员非好友功能。

在您的具体情况下,

append
(就地)需要修改现有的
string
,因此非常适合作为类方法,而
append
(复制)则不需要,所以(遵循指南)应该不是一个类方法。

因此:

void std::string::append(std::string const&);

inline std::string append(std::string left, std::string const& right) {
    left.append(right);
    return left;
}

根据大众的要求,这里有两个可用于优化性能的重载。首先是可以重用其参数缓冲区的成员版本:

void std::string::append(std::string&& other) {
    size_t const result_size = this->size() + other.size();

    if (this->capacity() < result_size) {
        if (other.capacity() >= result_size) {
            swap(*this, other);
            this->prepend(other);
            return;
        }
        // grow buffer
    }

    // append
}

其次是可以重用其右侧缓冲区的自由函数:

inline std::string append(std::string const& left, std::string&& right) {
    right.prepend(left);
    return right;
}

注意:我不确定是否存在不明确的重载。我相信不应该有...


0
投票

使用新的移动语义,您可以编写:

class A{
public:
    // this will get the property
    const dataType& PropertyName() const { return m_Property; }
    // this wil set the property
    dataType& PropertyName() { return m_Propery; }
private:
    dataType m_Propery;
};

main()
{
    A a;
    a.PropertyName() = someValueOfType_dataType; // set
    someOtherValueOfType_dataType = a.PropertyName(); // get
}

0
投票

这个问题我想了很多。一是提供该函数的两个版本:可变版本和不可变版本。

例如

class O {
  int a = 0;

public:
  O() { }
  O( const O &o ) : a( o.a ) { }

  O& increase() { ++a; return *this; }

  O copyIncrease() const {
    return O( *this ).increase();
  }
};

int main() {
  
  O o;
  o.increase();

  O o2 = o.copyIncrease();

}

我现在更倾向于的另一个解决方案是提供不可变的方法,而是提供一个明确请求对象副本的

.copy()
方法。然后,您可以在
.copy()

上运行可变函数
class O {
  int a = 0;

public:
  O() { }
  O( const O &o ) : a( o.a ) { }

  inline O copy() const { return *this; }
  O& increase() { ++a; return *this; }
};

int main() {
  
  O o;
  o.increase();

  O o2 = o.copy().increase();

}
© www.soinside.com 2019 - 2024. All rights reserved.