为什么我们需要传递 const 共享指针作为引用?

Why do we need to pass const shared pointer as reference?

在阅读开源代码时,我发现以下内容以两种不同的方式将共享指针传递给函数。

class A{A();};

typedef std::shared_ptr<A> A_Ptr;

void func1(A_Ptr a);

void func2( const A_Ptr& a);

在使用const时将其作为引用传递的原因是什么?我了解 func2 的作者不希望该函数能够更改 a 中的任何内容。但我们不能就这样 const A_Ptr a 吗?另外,我们不应该在 func1 中使用 A_Ptr & a 传递它的原因是什么?

以上代码在代码中出现:

Git: https://github.com/uzh-rpg/rpg_svo/

List of FramePtr in the code

void FrameHandlerMono::setFirstFrame(const FramePtr& first_frame)

void DepthFilter::addFrame(FramePtr frame)

But can't we just do this const FramePtr frame?

当然可以,但随后会调用复制构造函数,这适用于更大的类型(任何大于内置类型的类型)通常比通过引用传递更昂贵。这不是 shared_ptr 特有的。如果您不需要副本并且不想更改它们,通常应该默认通过 const 引用传递任何对象。只有 int、float 或 char 等内置类型应该按值传递。

更有趣的是为什么 func1 使用副本。最可能的情况是他无论如何都需要一份副本,因为他想在 class 中保留一个参考。我无法在您发布的 github 存储库中找到您所指的确切文件。如果还是不清楚请把func1的函数体绕过问题。

编辑:啊,我明白了。看起来他在这里按值传递的原因更多地与线程安全有关。没有阅读全部内容,但如果他通过 const 引用传递,shared_ptr 可能会被拥有线程删除。

例如,这里的 func 需要按值传递,否则指针可能会被主线程删除。可能是这样,但更复杂:

#include <chrono>
#include <iostream>
#include <memory>
#include <thread>

using namespace std::chrono_literals;

struct S {
    S() {}
};

void
//This signature would be false
//func(std::shared_ptr<S> const& s)
func(std::shared_ptr<S> s)
{
    std::cout << s.use_count() << '\n';
    std::this_thread::sleep_for(2s);
    //use_count would be 0 here if we pass by reference
    std::cout << s.use_count() << '\n';
}



int
main(int argc, char**) {
    std::shared_ptr<S> s{std::make_shared<S>()};

    std::thread t{func, std::ref(s)};

    std::this_thread::sleep_for(1s);

    s.reset();

    t.join();

    return 0;
}