【问题标题】:boost make_shared without template argument在没有模板参数的情况下提升 make_shared
【发布时间】:2017-03-17 17:59:00
【问题描述】:

我正在尝试将一个指向堆栈变量的指针传递给一个只需要boost::shared_ptr 的函数(我无法控制)。

根据this answer,使用boost::make_shared 是要走的路。为了测试这个功能,我写了这个:

#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>

int main(int argc, char const *argv[])
{
    int i = 10;
    boost::shared_ptr<int> int_ptr = boost::make_shared(i); // doesn't work
    some_function(int_ptr); // this function takes only shared_ptr
    return 0;
}

但它会引发以下错误:

error: no matching function for call to ‘make_shared(int&)’
boost::shared_ptr<int> int_ptr = boost::make_shared(i);
                                                     ^

如果我像这样添加模板参数,它可以工作,但这是什么原因?

boost::shared_ptr<int> int_ptr = boost::make_shared<int>(i);

谢谢!

【问题讨论】:

  • 问问自己,如果你只是给它一个int,函数应该是什么类型的共享指针。它怎么知道你想要shared_ptr&lt;int&gt; 而不是shared_ptr&lt;vector&lt;int&gt;&gt;,后者也可以由int 构造。
  • 请注意,模板参数推导不能包含有关结果将被分配到的类型的信息。在确定适当的模板参数时,不能考虑boost::shared_ptr&lt;int&gt; int_ptr = 部分。
  • 创建一个指向堆栈分配内存的shared_ptr 在尝试删除该内存时将是灾难性的。 i 是否需要通过指针进行修改,还是 i 的副本就足够了?
  • @chris i 不需要修改,一个副本就足够了,但我认为这就是使用make_shared 的全部意义所在。因为我必须将int_ptr 发送到的函数除了shared_ptr 之外不接受任何其他选项。
  • @simplename,嗯,问题指定了一个指向堆栈变量的指针。这不一定是make_shared 的重点。它避免了代码中的new,它对动态分配进行了优化,并防止在f(new A, new A)等情况下异常泄漏对象的可能性。

标签: c++ boost make-shared


【解决方案1】:

给定boost::make_shared&lt;T&gt; 模板:

namespace boost {
    template<typename T, typename Arg1>
      shared_ptr<T> make_shared( Arg1 const & arg1 );
}

模板机制可以推断出参数arg1的类型。因为它“看到”了参数i(即int)的类型。但是,它无法推断出返回类型T。它不知道您将分配给boost::shared_ptr&lt;T&gt;T 类型(即它无法知道int_ptr 的类型。)

boost::shared_ptr&lt;T&gt; 使用不同类型的参数 (Arg1) 和返回 (T) 以允许您从不同于指针类型的参数构建共享指针。比如doubleint

double d = 10.0;
std::shared_ptr<int> int_ptr = std::make_shared<int>(d);

如果要构建类型与参数相同的共享指针,可以编写一个包装器:

template<typename T>
boost::shared_ptr<T> my_make_shared(T const & arg) {
    return boost::make_shared<T>(arg);
}

但请记住,虽然这有效:

int i = 10.0;
std::shared_ptr<int> int_ptr = my_make_shared(i); // OK

隐式类型转换不会:

double d = 10.0;
std::shared_ptr<int> int_ptr = my_make_shared(d); // ERROR

希望对你有帮助!

【讨论】:

  • shared_ptr&lt;int&gt; 指向 double 是什么意思?
  • 实际上你没有指向doubleshared_ptr&lt;int&gt;。但是make_shared&lt;int&gt;int分配内存后,它用double的值初始化内存。
【解决方案2】:

虽然 Guilherme Ferreira 的答案详细说明了模板参数推导(并且在这方面是正确的),但我相信这不是您要寻找的答案。

我正在尝试将指向堆栈变量的指针传递给只需要 boost::shared_ptr 的函数(我无法控制)。

shared_ptr 表示对指向对象的共享所有权。如果你试图调用的函数将指针保存在它的一些数据结构中,比如一个容器,然后返回,那么一旦堆栈上的值被销毁,指针就会变得悬空,尽管shared_ptr仍然具有参考意义。为了做你想做的事,你必须绝对确保该函数不会将指针保存在任何地方,并且只能在这一次调用期间使用它。

只要满足这个条件,你就可以创建一个shared_ptr 指向堆栈上的一个值,但是你不能使用make_shared 来做这件事。 make_shared 在堆上分配一个新对象,并为其提供一个引用计数器,并使用您传递给函数调用的参数对其进行初始化。返回的shared_ptr 指向该新对象,而不是堆栈上的对象。

void foo()
{
    int n = 10;
    boost::shared_ptr< int > pn = boost::make_shared< int >(n);

    assert(*pn == 10); // succeeds
    assert(pn.get() == &n); // fails

    bar(pn);
}

这意味着bar 对指向int 的修改不会反映在n 上。

要为现有对象创建shared_ptr,您必须直接使用其构造函数。此外,由于对象的生命周期由堆栈控制,因此您必须禁止shared_ptr 销毁该对象。这可以通过在 shared_ptr 构造上指定无操作删除器来完成。

void foo()
{
    int n = 10;
    boost::shared_ptr< int > pn(&n, boost::null_deleter());

    assert(*pn == 10); // succeeds
    assert(pn.get() == &n); // succeeds

    bar(pn);
}

但请注意,此代码仍为引用计数器 shared_ptr 使用分配堆内存,因此您不会赢得任何性能。

【讨论】:

    猜你喜欢
    • 2012-05-03
    • 1970-01-01
    • 2012-10-11
    • 2021-09-14
    • 2011-04-11
    • 2013-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多