我想知道当将shared_ptr
void f(std::shared_ptr<const Widget> ){}
int main(){
std::shared_ptr<Widget> p;
f(p);
return 0;
}
我假设在这两种情况下我都为引用计数的增量和减量付费。
此外,我想知道如果我使用以下签名定义函数 f()
,为什么代码无法编译:
void f(shared_ptr<const Widget>& ){}
更让我惊奇的是,它确实做到了:
void f(const shared_ptr<const Widget>& ){}
最佳答案
为什么按值传递有效?
您的代码可以工作是因为 smart_ptr
constructor overload (9) :
template< class Y >
shared_ptr( const shared_ptr<Y>& r ) noexcept;
Constructs a shared_ptr which shares ownership of the object managed by r. If r manages no object, this manages no object too. The template overload doesn't participate in overload resolution if Y is not implicitly convertible to (until C++17)compatible with (since C++17) T*.
当该方法需要 shared_ptr<const Widget>&
时,为什么它无法编译? ?
如果您将签名更改为
void f(shared_ptr<const Widget>& ){}
您不能再一步完成转换并传递给方法,因为临时对象(转换产生的结果)无法绑定(bind)到非常量引用。但是,您仍然可以分两步完成:
int main(){
std::shared_ptr<Widget> p;
std::shared_ptr<const Widget> p2{p};
// f(p); // error: cannot bind non-const reference to temporary
f(p2); // OK
return 0;
}
有一些开销吗?
关于开销:是的,有一个 smart_ptr<const Widget>
被构造然后传递给方法(就像上面的代码片段中明确显示的那样)。
当该方法需要 const shared_ptr<const Widget>&
时,为什么它会再次起作用? ?
关于您的编辑,如果您将签名更改为以下内容,为什么它会再次起作用:
void f(const shared_ptr<const Widget>& ){}
在这种情况下,如果您传递 shared_ptr<Widget>
,仍有转换发生。但是,现在允许将转换产生的临时结果绑定(bind)到 const 引用。无论如何,该方法不允许修改它,因此允许传递临时值没有危险。
再举一个例子
请注意,临时变量不绑定(bind)到非常量引用是 C++ 的罕见情况,可帮助您避免愚蠢的错误。考虑一下:
void foo(int& x) { x += 2; }
int bar() { return 3; }
int main() { foo(bar()); } // error !
将右值传递给需要非常量左值引用的函数没有多大意义。您将无法观察 foo
所做的更改关于 bar
返回的值。
传递智能指针@cpp核心准则
关于将智能指针传递给函数,请注意 cpp coreguidelines有一些关于那的项目。底线是:如果该方法不参与引用计数(可能是最常见的情况),则不要传递智能指针,而是传递原始指针。
关于c++ - 指向函数签名中 const 的智能指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52591352/