一个类拥有一个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
)?
答案 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) {}
…
};