C++ 如何使用unique_ptr将const指针传递给const对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16425345/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to pass const pointer to const object using unique_ptr
提问by Yogeshwer Sharma
I want to pass a unique_ptr
to a helper function, and I want to make sure that the helper function neither modifies the pointer, nor the pointed object. Without the unique_ptr
, the solution is to have
我想将 a 传递unique_ptr
给辅助函数,并且我想确保辅助函数既不修改指针,也不修改指向的对象。没有unique_ptr
,解决方案是有
void takePtr(AClass const * const aPtr) {
// Do something with *aPtr.
// We cannot change aPtr, not *aPtr.
}
(Well, technically, AClass const * aPtr
is enough.) And I can call this with
(好吧,从技术上讲,AClass const * aPtr
就足够了。)我可以用
AClass * aPtr2 = new AClass(3);
takePtr(aPtr2);
I want to instead use unique_ptr
, but cannot figure out how to write this. I tried
我想改用unique_ptr
,但不知道如何写这个。我试过
void takeUniquePtr(unique_ptr<AClass const> const & aPtr) {
// Access *aPtr, but should not be able to change aPtr, or *aPtr.
}
When I call this with
当我用
unique_ptr<AClass> aPtr(new AClass(3));
takeUniquePtr(aPtr);
it does not compile. The error I see is
它不编译。我看到的错误是
testcpp/hello_world.cpp:141:21: error: invalid user-defined conversion from ‘std::unique_ptr<AClass>' to ‘const std::unique_ptr<const AClass>&' [-fpermissive]
Shouldn't the conversion from unique_ptr<AClass>
to unique_ptr<AClass const>
be automatic? What am I missing here?
转换不unique_ptr<AClass>
应该unique_ptr<AClass const>
是自动的吗?我在这里缺少什么?
By the way, if I change unique_ptr<AClass const> const & aPtr
to unique_ptr<AClass> const & aPtr
in the function definition, it compiles, but then I can call functions like aPtr->changeAClass()
, which I don't want to allow.
顺便说一下,如果我在函数定义中更改unique_ptr<AClass const> const & aPtr
为unique_ptr<AClass> const & aPtr
,它会编译,但是我可以调用类似 的函数aPtr->changeAClass()
,这是我不想允许的。
回答by syam
Smart pointers are for managing ownership and lifetime, they allow us (amongst other things) to safely transfer ownership around the various parts of our code.
智能指针用于管理所有权和生命周期,它们允许我们(除其他外)围绕代码的各个部分安全地转移所有权。
When you pass a const unique_ptr<T>&
to a function (irrelevant of whether T
is const
or not), what it actually means is that the function promises to never modify the unique_ptr
itself (but it could still modify the pointed-to object if T
is not const
) ie. there will be no possible transfer of ownership whatsoever. You're just using the unique_ptr
as a useless wrapper around a naked pointer.
当你传递一个const unique_ptr<T>&
给函数(无关是否T
是const
与否),它实际上意味着功能的承诺,永远不会改变unique_ptr
自己(但如果它仍可以修改所指向的对象T
是不是const
),即。无论如何都不可能转让所有权。您只是将unique_ptr
用作围绕裸指针的无用包装器。
So, as @MarshallClow suggested in a comment, you should just get rid of the wrapper and pass either a naked pointer or a direct reference. What's cool with this is that your code is now semantically clear(your function's signature clearly states that it does not mess with ownership, which was notimmediately obvious with a const unique_ptr<...>&
) and it solves your "constification" problem at the same time!
因此,正如@MarshallClow 在评论中建议的那样,您应该摆脱包装器并传递裸指针或直接引用。这样做的好处是,您的代码现在在语义上是清晰的(您的函数签名清楚地表明它不会与所有权混淆,而使用 a则不会立即明显const unique_ptr<...>&
)并且它同时解决了您的“结构化”问题!
Namely:
即:
void someFunction(const AClass* p) { ... }
std::unique_ptr<AClass> ptr(new AClass());
someFunction(ptr.get());
Edit:to address your secondary question "why won't the compiler let me ... cast unique_ptr<A>
to unique_ptr<A const>
?".
编辑:解决您的次要问题“为什么编译器不让我......强制转换unique_ptr<A>
为unique_ptr<A const>
?”。
Actually, you can movea unique_ptr<A>
to a unique_ptr<A const>
:
实际上,您可以将a移动unique_ptr<A>
到 a unique_ptr<A const>
:
std::unique_ptr<A> p(new A());
std::unique_ptr<const A> q(std::move(p));
But as you can see this means a transfer of ownership from p
to q
.
但正如您所看到的,这意味着所有权从 转移p
到q
。
The problem with your code is that you're passing a (reference to) unique_ptr<const A>
to a function. Since there is a type discrepancy with unique_ptr<A>
, to make it work the compiler needs to instantiate a temporary. But unless you transfer ownership manually by using std::move
, the compiler will try to copyyour unique_ptr
and it can't do that since unique_ptr
explicitly forbids it.
您的代码的问题在于您将 (reference to)unique_ptr<const A>
传递给 function。由于与 存在类型差异unique_ptr<A>
,为了使其工作,编译器需要实例化一个临时对象。但是除非您通过 using 手动转移所有权,否则std::move
编译器将尝试复制您的,unique_ptr
并且它不能这样做,因为unique_ptr
明确禁止它。
Notice how the problem goes away if you move the unique_ptr
:
请注意,如果您移动 ,问题将如何消失unique_ptr
:
void test(const std::unique_ptr<const int>& p) { ... }
std::unique_ptr<int> p(new int(3));
test(std::move(p));
The compiler is now able to construct a temporary unique_ptr<const A>
and move the original unique_ptr<A>
without breaking your expectations (since it is now clear that you want to move, not copy).
编译器现在能够unique_ptr<const A>
在unique_ptr<A>
不违背您的期望的情况下构建临时文件并移动原始文件(因为现在很明显您要移动,而不是复制)。
So, the root of the problem is that unique_ptr
only has move semantics not copy semantics, but you'd need the copy semantics to create a temporary andyet keep ownership afterwards.Egg and chicken, unique_ptr
just isn't designed that way.
因此,问题的根源在于unique_ptr
只有移动语义而不是复制语义,但是您需要复制语义来创建一个临时的并在之后保留所有权。鸡蛋和鸡肉,unique_ptr
只是不是那样设计的。
If you now consider shared_ptr
which hascopy semantics, the problem also disappears.
如果您现在考虑shared_ptr
哪个具有复制语义,问题也会消失。
void test(const std::shared_ptr<const int>& p) { ... }
std::shared_ptr<int> p(new int(3));
test(p);
//^^^^^ Works!
The reason is that the compiler is now able to create a temporary std::shared_ptr<const int>
copy(automatically casting from std::shared_ptr<int>
) and bind that temporary to a const
reference.
原因是编译器现在能够创建一个临时std::shared_ptr<const int>
副本(从 自动转换std::shared_ptr<int>
)并将该临时副本绑定到一个const
引用。
I guess this more or less covers it, even though my explanation lacks standardese lingo and is perhaps not as clear as it should be. :)
我想这或多或少涵盖了它,尽管我的解释缺乏标准的术语并且可能不像它应该的那样清晰。:)
回答by Amir Kirsh
Got to this old question on const smart pointers. Above answers ignore the simple template solution.
得到了这个关于 const 智能指针的老问题。以上答案忽略了简单的模板解决方案。
The very simple template option (option a)
非常简单的模板选项(选项 a)
template<class T>
void foo(const unique_ptr<T>& ptr) {
// do something with ptr
}
this solution allows all possible options of unique_ptr to be sent to foo:
此解决方案允许将 unique_ptr 的所有可能选项发送到 foo:
const unique_ptr<const int>
unique_ptr<const int>
const unique_ptr<int>
unique_ptr<int>
const unique_ptr<const int>
unique_ptr<const int>
const unique_ptr<int>
unique_ptr<int>
If you specifically want to avoid for some reason 3 and 4 above, add const to T:
如果您出于某种原因特别想避免上面的第 3 和第 4 条,请将 const 添加到 T:
Accept only const/non-const unique_ptr to const! (option b)
只接受常量/非常量 unique_ptr 到常量!(选项b)
template<class T>
void foo(const unique_ptr<const T>& ptr) {
// do something with ptr
}
Side note 1
旁注 1
You may overload "option a" and "option b" if to get different behavior for the cases where you can or cannot alter the pointed value.
如果要在可以或不能更改指向值的情况下获得不同的行为,则可以重载“选项 a”和“选项 b”。
Side note 2
旁注 2
If you do not want to make any changes to the pointed value in this function (never! whichever type of parameter we get!) -- do not overload.
With "option b", compiler won't allow to change the value we point at. Job done!
If you want to support all 4 cases, i.e. "option a", the function may still "accidentally" change the value we point to, e.g.
如果您不想对该函数中的指向值进行任何更改(永远不要!无论我们获得哪种类型的参数!) -不要重载。
使用“选项 b”,编译器将不允许更改我们指向的值。任务完成!
如果你想支持所有4种情况,即“选项a”,该函数仍然可能“不小心”改变我们指向的值,例如
template<class T>
void foo(const unique_ptr<T>& ptr) {
*ptr = 3;
}
however this should not be an issue if at least one caller has T that is actually const, the compiler will not like it in that case and help you get to the problem.
You may add such a caller in unit-test, something like:
但是,如果至少有一个调用者具有实际上是 const 的 T,那么这应该不是问题,在这种情况下编译器不会喜欢它并帮助您解决问题。
您可以在单元测试中添加这样的调用者,例如:
foo(make_unique<const int>(7)); // if this line doesn't compile someone
// is changing value inside foo which is
// not allowed!
// do not delete the test, fix foo!
Code snippet: http://coliru.stacked-crooked.com/a/a36795cdf305d4c7