当我今天检查一些代码的时候,我注意到一个实现std::enable_shared_from_this
的老方法,它在构造函数中保留一个std::weak_ptr
to self。
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
// use m_weak.lock() to access the object
//...
private:
X() {}
std::weak_ptr<X> m_weak;
};
但是我突然想到这个对象的constness。检查下面的代码:
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
void indirectUpdate() const {
m_weak.lock()->val = 1;
}
void print() const {
std::cout << val << '\n';
}
private:
X() {}
std::weak_ptr<X> m_weak;
int val = 0;
};
int main() {
auto x = X::create();
x->print();
x->indirectUpdate();
x->print();
}
在这段代码中,indirectUpdate()
是一个常量方法,它不应该更新我们的对象,但事实上它确实是这样的。因为std::weak_ptr.lock()
返回一个非常数shared_ptr<>
,即使方法是const。所以你可以在const方法中间接更新你的对象。这在std::enable_shared_from_this
的情况下不会发生,因为shared_from_this
返回一个指向const ref的共享指针。我想知道这段代码是不是UB。我觉得应该是,但我不确定。有什么想法吗?
更新日期:
对不起,我的问题似乎没有被正确地传达。我的意思是,即使我们有一个常量指针,我们也会通过这个方法失去常量性。下面的代码显示:
struct X {
static auto create() {
auto ret = std::shared_ptr<X>(new X);
ret->m_weak = ret;
return ret;
}
void show() const { std::cout << "const \n";}
void show() { std::cout << "non-const\n";}
void indirectUpdate() const {
show();
m_weak.lock()->show();
m_weak.lock()->val = 1;
}
void print() const {
std::cout << val << '\n';
}
int val = 0;
private:
X() {}
std::weak_ptr<X> m_weak;
};
int main() {
// Here we have a const pointer
std::shared_ptr<const X> x = X::create();
x->print();
x->indirectUpdate();
x->print();
}
输出如下:
0
const
non-const
1
表现为失稳。
1条答案
按热度按时间lvjbypge1#
修改的对象不是
const
。没有未定义的行为。添加如下方法:
要获得此输出,请执行以下操作:
通过const方法修改对象是可以的,只要该方法只修改实际上不是
const
的对象。这类似于对一个非常量对象使用
const &
,你可以抛弃constness并修改它,只要该对象真的不是const:我也没有看到在代码中误用模式的危险,因为一旦对象是
const
,就不能给它的val
成员赋值了,而使用constcorrection就可以了。在您的更新中,您在
main
中有一个const
指针,但对象仍然不是const
。请考虑以下更简单的示例:它和你的不太一样,但是它有类似的效果,在一个看似
const
的对象上调用一个非常量的方法。唯一的
foo
对象是在foo::create
中创建的,它不是常量。在main
中,我们有一个指向该对象的const foo*
。main
只能调用const
成员bar
。在bar
中,this
指针是一个const foo*
,但self
并不指向const foo
。self
本身是'const,但不是它所指向的对象。