使用std :: reference_wrapper <const t =“”>处理构造函数中的const T&-合适吗?

时间:2019-01-16 13:16:57

标签: c++ constructor reference const

一个类拥有一个U类型的对象。通过一种方法,它使用吸气剂将此对象公开为const U&(不可廉价复制,不需要修改)。

现在,一个客户端想要使用此API。他希望将U的实例用作复杂对象的一部分(对更改API对象没有兴趣)。 因此,他至少具有以下选择: 创建一个以T作为参数的类const U&和一个类型为const U&的私有字段,构造函数在其中存储API的实例。 这样做有一个极端的缺点,那就是使类的实例非常不灵活(例如,不使用std :: vectors进行管理),这是不希望的。

不久前,我发现人们还可以使用std::reference_wrapper<const U>来存储const U&,这不会对类型T的实例施加这些不利影响。

现在的问题是,这样做的行为是否像预期的那样,是一种好的做法吗?

在下面和here中,您可以找到使用此策略和所描述类型的有效代码。

#include <iostream>
#include <memory>

class U{
    public: 
    uint value;
};

class T{
private:
    std::reference_wrapper<const U> _u;

public:
    T(const U& u)
        :_u(u) {}

    const U& GetU(){
        return _u;
    }
};

const U& provideValue(U& u){
    return u;
}

int main()
{
    U internalApiValue;
    internalApiValue.value = 5;

    auto apiValue = provideValue(internalApiValue);

    T container(apiValue);

    std::cout << container.GetU().value;
}

我想如果这不是一个好主意,唯一的选择就是避免使用const,因为否则我会对此类方法的用户施加严格的限制(公开const U&而不是U&的方法或U)?

2 个答案:

答案 0 :(得分:2)

界面的一个主要问题是T的唯一构造函数使用const U&。这意味着您可以将临时变量传递到T并留下reference_wrapper到死对象,因为对象中的const&不会延长临时变量的寿命。

要解决此问题,您需要添加一个已删除的构造函数,以阻止您接受临时对象。添加

T(const U&&) = delete;

会做到这一点。

答案 1 :(得分:1)

这应该在做您想要的。它按预期使用的方式使用std::reference_wrapper<T>(以可复制和可分配的方式传递引用)。我没有发现任何问题。来自cppreference.com

  

std :: reference_wrapper是一个类模板,它将引用包装在可复制的可分配对象中。它通常用作将引用存储在通常无法保存引用的标准容器(如std :: vector)内的机制。

我看到的唯一潜在弊端是std::reference_wrapper<T>可能会有点笨拙并且对某些人不熟悉。解决您的问题的更常见方法可能是将指针存储在对象中,而不是引用中。例如:

class T {
private:
    const U* _u;

public:
    T(const U& u)
        : _u(&u) {}
    …
};