【问题标题】:Variadic templates with const references带有 const 引用的可变参数模板
【发布时间】:2017-08-28 14:07:31
【问题描述】:

我的项目使用自定义分配器,它通过以下方式构造对象:

template <typename T, typename... Args>
T* create(Args... args)
{
    T* object = // request "bare" memory
    // call object constructor
    return new(reinterpret_cast<void*>(object)) T(args...);
}

有一个类,包含常量引用作为字段:

struct A {
  A(const string& s) : str_(s) {
    cout << &s << '\n';
  }

  const string& str_;
};

但是当我尝试创建一个对象时,我得到了错误的结果:

string* str = new string("some string");
cout << str << '\n';
A* a = create<A>(*str);

输出:

0x7fffc8004db4
0x7fffd5436050

我认为 const 引用字段 (str_) 应该包含与工程机械相同的地址,但显然不是这样。

为什么会发生,如何避免?

Ofc,我忍不住要使用自定义分配器,这是强制性的,我不会问。

【问题讨论】:

    标签: c++ c++11 memory-management pass-by-reference variadic-templates


    【解决方案1】:

    电话

    A* a = create<A>(*str);
    

    创建*str 的副本并使用该副本调用函数,因为函数被声明为

    template <typename T, typename... Args>
    T* create(Args... args) {...}
    

    a 引用了一个不再存在的对象。

    使用

    template <typename T, typename... Args>
    T* create(Args&&... args)
    {
       T* object = // request "bare" memory
       // call object constructor
       return new(reinterpret_cast<void*>(object)) T(std::forward<Args>(args)...));
    }
    

    改为。

    【讨论】:

    • 完美转发难道不比const&amp;获取更好,然后将它们复制到构造函数中吗?
    • @Rakete1111,是的,它会的。由于我仍然在 VS2008 中工作,因此我不会首先想到使用完美转发 :) :)
    【解决方案2】:
    template <typename T, typename... Args>
    T* create(Args... args)
    {
        T* object = // request "bare" memory
        // call object constructor
        return new(reinterpret_cast<void*>(object)) T(args...);
    }
    

    您的所有可变参数都将按值传递。因此正在制作副本。您可能想使用转发引用:

    template <typename T, typename... Args>
    T* create(Args&&... args)
    {
        auto memory =  // request "bare" memory
        // call object constructor
        return new(memory) T(std::forward<Args>(args)...);
    }
    

    打印:

    0x111ac20
    0x111ac20
    

    Demo


    在您想使用 placement-new 时再次考虑数据对齐。

    【讨论】:

    • 对不起,也许我遗漏了一些东西...除了分配一块大小为sizeof(T) 的内存之外,还有其他关于对齐的条件吗? sizeof 不报告已经对齐的大小吗?
    猜你喜欢
    • 2012-05-02
    • 2014-09-08
    • 2016-10-10
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-20
    • 2015-12-14
    相关资源
    最近更新 更多