C ++通过Passed Reference修改self

时间:2016-06-15 03:18:25

标签: c++ object reference self mutable

我想是一种最佳实践问题。

在C ++中,我有一个类似于Python的os.path的文件系统路径的包装类。在这个包装器类中,有一个名为“Split”的成员函数,它搜索最后出现的路径分隔符并将其拆分为“tail”(路径的最后一部分)和“head”(其他所有内容)。就目前而言,该函数使用自己的成员变量m_filepath进行拆分。

一些代码:

class FilePath {
    public:
        void Split(FilePath& head, FilePath& tail) const
        {
            FilePath h;
            FilePath t;
            //initialize h, t with portions of m_filepath...
            head = h;
            tail = t;
        }
    private:
        std::string m_filepath;
};

int main(int argc, char ** argv)
{
    FilePath some_path_1("/");
    FilePath some_path_2("/home/");
    some_path_1.Split(some_path_1, some_path_2);
    return 0;
}

当我做这样的事情时,some_path_1的m_filepath会被所谓的“head”覆盖。 const运算符似乎也不介意。

我的问题是,处理这个问题的最佳方法是什么?抛出异常?允许覆盖对象(这让我担心,听起来不安全)并告诉开发人员要谨慎吗?巧妙地使用return语句?

2 个答案:

答案 0 :(得分:1)

以这种方式编写代码的一个大问题是清理代码的诱惑,以便拆分看起来像这样:

void Split(FilePath & h, FilePath & t) {
  h.m_filepath = getHead(m_filepath);
  t.m_filepath = getTail(m_filepath);
}

但是,由于h.m_filepath = ...实际上正在改变this.m_filepath,所以第二个电话不会做预期的事情。 (请注意,您的代码目前很好 - 但很脆弱)。

(潜在)问题的根源是使用引用作为返回值并需要多个返回值的组合。但是C ++ 11通过tie支持多个返回值。

所以我将其实现为

class FilePath {
    public:
        std::pair<FilePath,FilePath> Split() const
        {
            FilePath h;
            FilePath t;
            //initialize h, t with portions of m_filepath...
            head = h;
            tail = t;
            return std::make_pair(h,t);
        }
    private:
        std::string m_filepath;
};

然后用法如下:

int main(int argc, char ** argv)
{
    FilePath some_path_1("/");
    FilePath some_path_2("/home/");
    std::tie(some_path_1, some_path_2) = some_path_1.Split();
    return 0;
}

很明显,some_path_1some_path_2会更新其值,而且您不必担心对参数的写入会改变这一点,因为不再有任何参数

答案 1 :(得分:0)

编辑啊!我刚刚意识到您希望Split()做什么:将this分成headtail - 并希望它们不会将this传递给head 1}}也不tail

在另一种情况下,operator =(Class &rhs)最佳做法是首先将&rhsthis进行比较,以避免出现这个问题 - 但我认为您无论如何都不会遇到这个问题。在你给出的用法中,不仅清楚会发生什么,你的实现还是足以让它发生。我不担心(正如@ M.M所说)。

当你有一个成员函数时,期望函数将在类的实例上运行:即Split()本身关闭,或者放弃一些关于它自己的信息。

你想要的是一个static成员函数:一个函数,它与它的类相关联,不会对假定的this起作用。制作Split()函数static

static void Split(...); // Note no concept of const required - no `this` to modify!

并称之为:

FilePath::Split(some_path_1, some_path_2);

或者,您可以使Split()返回尾部,并将其自身修改为头部:

FilePath Split();

但在这种情况下,分裂发生的方向有点模糊。怎么样:

FilePath SplitHead();

FilePath SplitTail();

最后两个可以用上面的static方法实现,如下所示:

FilePath FilePath::SplitHead() {
    FilePath head = *this;
    Split(head, *this);
    return head;
} // FilePath::SplitHead()

FilePath FilePath::SplitTail() {
    FilePath tail;
    Split(*this, tail);
    return tail;
} // FilePath::SplitTail()