如果我定义了相同类型的shared_ptr
和const shared_ptr
,请执行以下操作:
std::shared_ptr<int> first = std::shared_ptr<int>(new int);
const std::shared_ptr<int> second = std::shared_ptr<int>();
稍后尝试像这样更改const shared_ptr
的值:
second = first;
它会导致编译错误(应该如此)。但即使我试图抛弃const部分:
(std::shared_ptr<int>)second = first;
上面代码的结果是second
最终为空,而first
未被触及(例如,引用计数仍为1)。
如何在最初设置后更改const shared_ptr
的值?这对std的指针来说甚至可能吗?
谢谢!
答案 0 :(得分:3)
在构造或销毁之外以任何方式修改声明为const
的变量是未定义的行为。
const std::shared_ptr<int> second
这是一个声明为const
的变量。
在构造之后和销毁之前,没有标准的合规方式来改变它所指的内容。
话虽这么说,手动调用析构函数并在同一地点构建新的shared_ptr
可能是合法的,我不确定。你肯定不能用它的原始名称来引用shared_ptr
,并且可能离开原始shared_ptr
存在的范围是非法的(因为析构函数试图破坏原始对象,根据{{1}}对象的构造方式,编译器可以证明的空共享指针(或非空指针)。
即使您可以在标准允许的情况下进行论证,这也是一个坏主意。
const
个对象无法更改。
...
您投射到const
只会创建一个临时副本。然后将其分配给,并更改临时副本。然后丢弃临时副本。未被修改的shared_ptr<int>
是预期的行为。分配给临时副本的合法性是因为const shared_ptr<int>
并且大多数shared_ptr
库是在我们能够根据左边的r / lvalue-ness重载std
之前设计的。手边。
...
现在,为什么会这样呢?编译器将实际operator=
ness用作优化提示。
const
在上面的例子中,编译器可以知道某些,{
const std::shared_ptr<int> bob = std::make_shared<int>();
}
在范围的末尾是非空的。 bob
没有任何东西可以使它变空,但仍然会让你有明确的行为。
因此,在销毁检查指针是否为空的bob
时,编译器可以消除作用域末尾的分支。
如果将bob
传递给检查bob
的空状态的inline
函数,则可能会发生类似的优化;编译器可以省略检查。
假设您将bob传递给
bob
编译器无法看到void secret_code( std::shared_ptr<int> const& );
的实现。它可以假设密码不会编辑bob 。
如果没有声明secret_code
,const
可以合法地对参数执行secret_code
并将其设置为null;但如果const_cast<std::shared_ptr&>
的参数实际上是secret_code
,则这是未定义的行为。 (任何代码转换为const都有责任保证不会实际修改实际的const
值)
const
上没有const
,编译器无法保证:
bob
将打印{
const std::shared_ptr<int> bob = std::make_shared<int>();
secret_code(bob);
if (bob) {
std::cout << "guaranteed to run"
}
}
字符串。
guaranteed to run
上const
,编译器可以自由地取消上面的bob
检查。
...
现在,请不要混淆我的解释,因为为什么标准声明您无法使用&#34编辑if
堆栈变量;如果没有发生则没有问题&# 34 ;.标准规定你不应该这样做;如果你这样做的后果是无限的,并且可以随着你的编译器的新版本而增长。
...
来自评论:
对于反序列化进程,它实际上是一种从文件反序列化对象的构造函数。 C ++很不错,但它有其不完美之处,有时可以搜索不那么正统的方法。
如果是构造函数,请将其设为构造函数。
在C ++ 17中,返回const
的函数在很多方面与真正的构造函数基本相同(由于保证省略)。在C ++ 14中,这不是真的(你还需要一个移动构造函数,编译器需要忽略它)。
因此,C ++中类型T
的反序列化构造函数需要返回T
,它不能通过引用获取T
并且是真正的构造函数。
编写这个有点痛苦,但可以做到。使用相同的代码进行序列化和反序列化更是一种痛苦(我无法解决这些问题)。