自定义引用类型
Custom reference type
我正在写一个 C-API 的包装器。
(i) 设 capi_array_data capi_get_array(void)
为包含在该库中的函数,返回一个结构,该结构包含关于由所述 API 管理的堆分配数组的元数据。它看起来像 struct capi_get_array { size_t length; int* arr };
(为简单起见,使用 int
)
(ii) 这样的数组可以由用户用malloc
、new
、std::vector
等手动创建,然后必须用void capi_register_array(int*)
注册.
我想做一个包装器class,称之为MyArrayWrapper
,用STL容器的结构来管理这样一个数组,支持operator[]
,begin
, back
,等等。在 (i) 中这个包装器不会拥有数据,但在 (ii) 中它会。我现在的问题是,我是否应该
(a) 有一个 class 可以使用 std::initializer_list
(或与此相关的可变参数模板)或 [=56= 返回的 int*
构造];
(b) 有单独的 classes 命名为 MyArrayWrapperRef
和 MyArrayWrapper
,第一个处理 (i) 和第二个处理 (ii);
(c) 对于 (i) 最好使用语法 MyArrayWrapper&
,对于 (ii) 使用 MyArrayWrapper
;这可以做到吗?
(a) 可能会引起混淆,因为一个 class 做两件事,这打破了单一职责原则。 "does the copy constructor conduct a deep of shallow copy?" 等问题的答案并不明显,需要进一步的文档。
(b) 似乎是个不错的选择,但现在有多种情况:MyArrayWrapper
、MyArrayWrapper&
、MyArrayWrapperRef
、MyArrayWrapperRef&
。他们会有什么不同? const
参考文献呢?这甚至可能需要另一个 class MyArrayWrapperConstRef
并再次导致混淆。
(c) 是最佳的,并且与其他 classes 一起看起来很自然,但我不知道有什么方法可以让它发挥作用。我可以围绕 capi_get_array
做一个包装,返回一个 MyArrayWrapperRef
,但我必须将引用的来源保存在某处,对吗?
With (a) there could come up confusion, as one class does two things,
which breaks the single-responsibility principle.
您也可以反过来看:包装器 的唯一职责是 隐藏真正的所有权以及谁清理什么。
假设你有这个:
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 only\n";
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 both\n";
delete[] x->a;
delete x;
})};
}
int main(){
auto v = make_owning_wrapper();
auto w = make_non_owning_wrapper();
auto z = v;
}
使用共享指针,您可以选择 a) 清理时要做什么以及 b) 复制 wrapper
时会发生什么,而不会造成很大的混乱;)。
我正在写一个 C-API 的包装器。
(i) 设 capi_array_data capi_get_array(void)
为包含在该库中的函数,返回一个结构,该结构包含关于由所述 API 管理的堆分配数组的元数据。它看起来像 struct capi_get_array { size_t length; int* arr };
(为简单起见,使用 int
)
(ii) 这样的数组可以由用户用malloc
、new
、std::vector
等手动创建,然后必须用void capi_register_array(int*)
注册.
我想做一个包装器class,称之为MyArrayWrapper
,用STL容器的结构来管理这样一个数组,支持operator[]
,begin
, back
,等等。在 (i) 中这个包装器不会拥有数据,但在 (ii) 中它会。我现在的问题是,我是否应该
(a) 有一个 class 可以使用 std::initializer_list
(或与此相关的可变参数模板)或 [=56= 返回的 int*
构造];
(b) 有单独的 classes 命名为 MyArrayWrapperRef
和 MyArrayWrapper
,第一个处理 (i) 和第二个处理 (ii);
(c) 对于 (i) 最好使用语法 MyArrayWrapper&
,对于 (ii) 使用 MyArrayWrapper
;这可以做到吗?
(a) 可能会引起混淆,因为一个 class 做两件事,这打破了单一职责原则。 "does the copy constructor conduct a deep of shallow copy?" 等问题的答案并不明显,需要进一步的文档。
(b) 似乎是个不错的选择,但现在有多种情况:MyArrayWrapper
、MyArrayWrapper&
、MyArrayWrapperRef
、MyArrayWrapperRef&
。他们会有什么不同? const
参考文献呢?这甚至可能需要另一个 class MyArrayWrapperConstRef
并再次导致混淆。
(c) 是最佳的,并且与其他 classes 一起看起来很自然,但我不知道有什么方法可以让它发挥作用。我可以围绕 capi_get_array
做一个包装,返回一个 MyArrayWrapperRef
,但我必须将引用的来源保存在某处,对吗?
With (a) there could come up confusion, as one class does two things, which breaks the single-responsibility principle.
您也可以反过来看:包装器 的唯一职责是 隐藏真正的所有权以及谁清理什么。
假设你有这个:
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 only\n";
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 both\n";
delete[] x->a;
delete x;
})};
}
int main(){
auto v = make_owning_wrapper();
auto w = make_non_owning_wrapper();
auto z = v;
}
使用共享指针,您可以选择 a) 清理时要做什么以及 b) 复制 wrapper
时会发生什么,而不会造成很大的混乱;)。