我想是一种最佳实践问题。
在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语句?
答案 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_1
和some_path_2
会更新其值,而且您不必担心对参数的写入会改变这一点,因为不再有任何参数
答案 1 :(得分:0)
编辑啊!我刚刚意识到您希望Split()
做什么:将this
分成head
和tail
- 并希望它们不会将this
传递给head
1}}也不tail
。
在另一种情况下,operator =(Class &rhs)
最佳做法是首先将&rhs
与this
进行比较,以避免出现这个问题 - 但我认为您无论如何都不会遇到这个问题。在你给出的用法中,不仅清楚会发生什么,你的实现还是足以让它发生。我不担心(正如@ 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()