【发布时间】:2022-01-02 23:16:50
【问题描述】:
对于一个严格的内部类,不是旨在用作提供给外部客户端的 API 的一部分,初始化类指针有什么本质上的邪恶吗成员变量本身而不是NULL 或nullptr?
请参见下面的代码示例。
#include <iostream>
class Foo
{
public:
Foo() :
m_link(this)
{
}
Foo* getLink()
{
return m_link;
}
void setLink(Foo& rhs)
{
m_link = &rhs;
// Do other things too.
// Obviously, the name shouldn't be setLink() if the real code is doing multiple things,
// but this is a code sample.
}
void changeState()
{
// This is a code sample, but play along and assume there are actual states to change.
std::cout << "Changing a state." << std::endl;
}
private:
Foo* m_link;
};
void doSomething(Foo& foo)
{
Foo* link = foo.getLink();
if (link == &foo)
{
std::cout << "A is not linked to anything." << std::endl;
}
else
{
std::cout << "A is linked to something else. Need to change the state on the link." << std::endl;
link->changeState();
}
}
int main(int argc, char** argv)
{
Foo a;
doSomething(a);
std::cout << "-------------------" << std::endl;
// This is a mere code sample.
// In the real code, I'm fetching B from a container.
Foo b;
a.setLink(b);
doSomething(a);
return 0;
}
输出
A is not linked to anything.
-------------------
A is linked to something else. Need to change the state on the link.
Changing a state.
优点
将指针变量 Foo::link 初始化为自身的好处是可以避免意外的 NULL 取消引用。由于指针永远不能为 NULL,那么最坏的情况是程序会产生错误输出而不是分段错误。
缺点
但是,这种策略的明显缺点是它似乎是非常规的。大多数程序员习惯于检查 NULL,因此不期望检查与调用指针的对象是否相等。因此,不建议将此技术用于针对外部消费者的代码库,即希望将此代码库用作库的开发人员。
结语
其他人有什么想法吗?有没有其他人在这个主题上发表过任何实质性的言论,尤其是考虑到 C++98 ?请注意,我使用带有以下标志的 GCC 编译器编译了此代码:-std=c++98 -Wall,但没有发现任何问题。
附:请随时编辑这篇文章以改进我在这里使用的任何术语。
编辑
- 这个问题是本着其他良好实践问题的精神提出的,例如这个关于deleting references 的问题。
- 提供了一个更广泛的代码示例来消除混淆。具体来说,样本现在是 63 行,比最初的 30 行有所增加。因此,变量名称已更改,因此引用
Foo:p的 cmets 应适用于Foo:link。
【问题讨论】:
-
“在最坏的情况下,程序会产生错误的输出而不是分段错误”这实际上是有益的吗?阅读快速失败的想法。
-
@user17732522 目的是防止其他程序员,包括我自己,忘记检查 NULL 并随后导致分段错误。这个微服务绝对不会崩溃。错误输出也很糟糕,但总比崩溃好。
-
假设您没有忘记复制构造函数/赋值运算符,也许只是删除它们。我发现它使用了这种模式:en.wikipedia.org/wiki/…(尽管它不是最好的例子),我隐约记得一些数据结构可以做到这一点。它类似于null object pattern(例如,如果它是一个单链表,你可以拥有
size_t length() const { return p == this ? 0 : 1 + p->length() },而不必担心在nullptr上调用成员函数) -
@user17732522 假设
p被初始化为NULL。然后每次我需要检索p时,我都需要检查NULL。如果我忘记检查NULL,我的程序就会崩溃。当然,我会进行单元测试以确保我的程序没有错误,但万一我错过了什么,我真的不希望我的程序崩溃。 -
@Frisky - 我想这取决于您的应用程序域。我曾经在一家银行工作,在那里我们因稍有怀疑不正确的结果而中止了交易。 什么都好 比向客户显示帐户余额不正确要好。 YMMV,等等。
标签: c++ pointers initialization class-design c++98