【发布时间】:2020-11-17 21:47:24
【问题描述】:
为什么以下是合法的?
std::shared_ptr<const Foo> foo = std::make_shared(new Foo());
Foo bar = *foo;
取消对const Foo的引用不应该是合法的吗?
【问题讨论】:
为什么以下是合法的?
std::shared_ptr<const Foo> foo = std::make_shared(new Foo());
Foo bar = *foo;
取消对const Foo的引用不应该是合法的吗?
【问题讨论】:
因为你已经调用了复制构造函数,并且新创建的变量不会影响原始变量。这是一样的
const int x = 3
int y = x;
x被复制到y,这样就没有问题了。然而,这是非法的:
Foo *bar = foo;
或者这个
Foo &bar = *foo;
当然,编译器只是以“浅”的方式检查这个,所以你绝对可以自己 FooBar。要求编译器做得更好是太难了。一个内存泄漏的例子(泄漏不是重点,我只是懒惰):
#include<memory>
#include<iostream>
struct Foo {
int *x;
Foo(int x) : x(new int(x)) {}
};
int main() {
std::shared_ptr<const Foo> foo = std::make_shared<Foo>(3);
Foo bar = *foo;
*bar.x = 5;
std::cout<<*foo->x<<"\n";
return 0;
}
输出是 5... 这种类型的错误很糟糕,并且使诸如 3 规则(5 等)和 const 正确性(在您的所有代码中)之类的东西很重要。事实上,你甚至不必那么努力。这也“打破”了:
#include<memory>
#include<iostream>
struct Foo {
int *x;
Foo(int x) : x(new int(x)) {}
};
int main() {
std::shared_ptr<const Foo> foo = std::make_shared<Foo>(3);
*foo.x = 5;
std::cout<<*foo->x<<"\n";
return 0;
}
这种行为对于 C++ 来说并不特殊。在我的脑海中,Python 中包含列表的元组是另一个通常被认为是 const 但可以更改的示例。
我猜你可以称之为“浅常量”,因此,这是预期的行为,而不是真正的错误,尽管通常是它们的原因 - const 保证对象,而不是其中包含的任何内容(如果它是一个容器,则包含比对象的字段更“内部”的层次上的含义)。一些容器可能会提供额外的保证,但必须实施。
【讨论】:
bar 是原始 foo 的全新副本。它调用什么方法有什么关系?