自定义引用类型

Custom reference type

本文关键字:引用类型 自定义      更新时间:2023-10-16

我正在围绕C-API编写一个包装器。

(i( 让capi_array_data capi_get_array(void)成为此库中包含的函数,返回一个结构,其中包含有关由所述 API 管理的堆分配数组的元数据。它看起来像struct capi_get_array { size_t length; int* arr };(为简单起见,使用int(

(ii( 这样的数组可以由用户手动创建,包括mallocnewstd::vector等。然后必须向void capi_register_array(int*)注册。

我想做一个包装类,称之为MyArrayWrapper,用STL容器的剖析来管理这样一个数组,支持operator[]beginback等。在 (i( 中,此包装器将不拥有数据,但在 (ii( 中,它将拥有数据。我现在的问题是,我是否应该

(a( 有一个可以使用std::initializer_list(或可变参数模板(或 API 返回的int*构造的单个类;

(b(有单独的类,命名为MyArrayWrapperRefMyArrayWrapper,第一个处理(i(和第二个处理(ii(;

(c( 最好有 (i( 的语法MyArrayWrapper&和 (ii( 的语法MyArrayWrapper;可以这样做吗?

对于(a(可能会出现混淆,因为一个类做两件事,这打破了单一责任原则。对于诸如"复制构造函数是否执行深层浅层复制?"之类的问题的答案并不明显,需要进一步的文档。

(b(似乎是一个不错的选择,但现在有多种情况:MyArrayWrapperMyArrayWrapper&MyArrayWrapperRefMyArrayWrapperRef&。它们会有什么不同?const参考呢?这甚至可能需要另一个类MyArrayWrapperConstRef并再次导致混淆。

(c(是最佳的,对于其他类来说似乎是自然的,但我不知道有什么方法可以让它工作。我可以在返回MyArrayWrapperRefcapi_get_array周围做一个包装器,但我必须将引用的来源保存在某个地方,对吧?

对于(a(可能会出现混淆,因为一个类做两件事, 这打破了单一责任原则。

你也可以反过来看:包装器的唯一职责隐藏真正的所有权以及谁清理了什么。

假设你有这个:

struct arr_data {
int* a;
unsigned size;
};
arr_data get_arr(){
arr_data ret;
ret.size = 5;
ret.a = new int[ret.size];
return ret;
}
void reg_arr(arr_data x){
static arr_data store = x;
}

那么一个简单的包装器可能看起来像这样:

struct wrapper {
std::shared_ptr<arr_data> data;
// implement container-like interface
};
wrapper make_non_owning_wrapper() { 
auto res = new arr_data();
*res = get_arr();
return { std::shared_ptr<arr_data>(res,[](arr_data* x){
std::cout << "delete x onlyn";
delete x;
}) };
}
wrapper make_owning_wrapper() {
auto res = new arr_data();
res->size = 5;
res->a = new int[res->size];
return { std::shared_ptr<arr_data>(res,[](arr_data* x){
std::cout << "delete bothn";
delete[] x->a;
delete x;
})};
}
int main(){
auto v = make_owning_wrapper();
auto w = make_non_owning_wrapper();
auto z = v;
}

使用共享指针,您可以选择 a( 清理时要做什么,b( 复制wrapper时会发生什么,而不会引起很大的混乱;)。