如何在 Visual Studio 中解决 make_shared 的 10 个限制

Posted

技术标签:

【中文标题】如何在 Visual Studio 中解决 make_shared 的 10 个限制【英文标题】:How to work around 10 limit for make_shared in Visual Studio 【发布时间】:2013-01-15 17:12:48 【问题描述】:

在一些旧代码上使用 C++10 的新功能时,我遇到了一个问题,即我无法调用需要 12 个参数的make_shared。我记得微软的 STL 谈到他们如何使用模拟 make_shared 并且最多 10 个。 显然,仅仅为此重构代码是不可能的,所以基本上我的问题是 - 有没有办法在 VS 2010 中获得超过 10 个参数到 make_shared

【问题讨论】:

尝试将/D_VARIADIC_MAX=12 添加到编译器选项中。我记得读过你只能将它增加到 10,但值得一试。 @Praetorian blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx 说限制是 5 到 10(含)。 "显然,仅仅为了这个而重构代码是不可能的" 重构代码怎么样,因为有 10 个参数的构造函数显然在乞求重构? @NicolBolas 实际上没有。我不想泄露专家的商业机密(写 12 arg ctor 类的大师:D),但相信我,它不是一个普通的类,更像是一个味精。 :D 【参考方案1】:
make_shared<foobar>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);

可以替换为

shared_ptr<foobar>(new foobar(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12));

在 C++11 中,std::make_shared 实际上是对使用第二种方法创建对象的性能优化,因为它只执行一次内存分配而不是两次,但是一旦超过 10 个变量,你就不会有很多选择。

【讨论】:

Doh,我太愚蠢了... shared_ptr 不在乎 T ctor args 的数量,只有 make_shared 中的假可变参数是限制... tnx 现在应用并测试它,从我看到它有效。 :) make_shared 对于编写异常安全的代码也很有用。如果您使用这种方式,请给每个 shared_ptr 一个名称,不要将它们作为临时对象传递。【参考方案2】:

如果您真的想使用make_shared 的效率优势,那么您仍然可以这样做:

#include <tuple>
#include <memory>
#include <redi/index_tuple.h>

template<typename X, typename... Args>
  std::shared_ptr<X>
  make_shared_TO_THE_MAX(Args&&... args)
  
    struct Wrapper
    
      X x;

      template<typename... T>
        Wrapper(std::tuple<T...> targs) : Wrapper(targs, to_index_tuple<T...>)  

      template<typename T, unsigned... I>
        Wrapper(T targs, index_tuple<I...>) : x(std::get<I>(targs))  
    ;

    auto wrapped = std::make_shared<Wrapper>(std::forward_as_tuple(std::forward<Args>(args)...));
    return std::shared_ptr<X>(wrapped, &wrapped->x);
  

这会将构造函数参数捆绑成一个引用元组并将其传递给make_shared,因此make_shared 不能处理10 个参数并不重要,因为它只能得到一个。而不是make_shared&lt;X&gt;,它使用make_shared&lt;Wrapper&gt;,它将为Wrapper(其大小和布局与其X类型的成员相同)分配空间,并使用参数元组构造它。 Wrapper 构造函数委托给另一个构造函数,该构造函数扩展元组以传递给 X 构造函数。

最后,它使用shared_ptr 别名构造函数返回与shared_ptr&lt;Wrapper&gt; 共享所有权但存储X 对象的地址的shared_ptr&lt;X&gt;

&lt;redi/index_tuple.h&gt; 是 my own header,但我正在尝试使 something similar 标准化为 C++14。

这也可以在没有可变参数模板的情况下完成,但工作量更大。这里是两个参数,十二个再加十个!

#include <tuple>
#include <memory>

template<typename X, typename Arg0, typename Arg1>
  std::shared_ptr<X>
  make_shared_TO_THE_MAX(Arg0&& arg0, Arg1&& arg1)
  
    struct Wrapper
    
      X x;

      template<typename T0, typename T1>
        Wrapper(std::tuple<T0, T1> targs)
        : x(std::get<0>(targs), std::get<1>(targs))  
    ;

    auto wrapped = std::make_shared<Wrapper>(std::forward_as_tuple(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1)));
    return std::shared_ptr<X>(wrapped, &wrapped->x);
  

【讨论】:

等等,不是... var 模板吗?如果是这样,那么:(因为:“有没有办法在 VS 2010 中获得超过 10 个参数来 make_shared。” 它不会将超过 10 个参数传递给 make_shared,这就是重点。但它确实使用了可变参数。我在想编译器支持可变参数但 stdlib 不支持,但我认为这仅适用于最新的编译器更新。您仍然可以在没有可变参数的情况下完成上述技巧,只需手动列出您的类型需要的 12 个参数,然后使用 std::get&lt;0&gt;(t), std::get&lt;1&gt;(t), std::get&lt;2&gt;(t), 等显式解包元组。如果 tuple 也有十个限制,您需要传递两个元组。

以上是关于如何在 Visual Studio 中解决 make_shared 的 10 个限制的主要内容,如果未能解决你的问题,请参考以下文章

visual studio乱码怎么办 vs繁体中文乱码问题解决方法

如何强制在 Visual Studio 2013 中打开解决方案文件 (SLN)?

启动visual studio 2008后显示对话框: visual studio的试用版评估期已结束。 如何解决。

visual studio 如何生成动态库

如何更改解决方案资源管理器的字体大小(在 Visual Studio 中)

如何在 Visual Studio 3 中添加 Visual Studio 5 项目?