C - 从 C++ 模拟 'mutable'
C - emulate 'mutable' from C++
我有这样的 C 结构:
struct my_struct {
int i;
double d;
struct expensive_type * t;
};
此结构的实例已创建并初始化为:
struct my_struct * my_new( int i , double d)
{
struct my_struct * s = malloc( sizeof * s);
s->i = i;
s->d = d;
s->t = NULL;
return s;
}
计算 struct expensive_type * t
成员非常昂贵,可能不需要 - 因此它只是初始化为 NULL
- 然后按需计算:
const struct expensive_type * my_get_expensive( const struct my_struct * s)
{
if (!s->t)
s->t = my_expensive_alloc( s->i , s->d );
return s->t;
}
在 C++ 中,我会在 struct expensive_type *
成员上使用 mutable
,是否有可能在 C 中实现类似的东西,即在本地丢弃常量:
{
struct my_struct * mutable_s = (struct my_struct*) s;
mutable_s->t = ...;
}
或者删除签名中的 const
是我唯一符合标准的选择吗?
您可以(1)重构您的代码并添加一个间接层:
struct expensive; // Forward declaration, ignore
// One could also use a struct expensive * (a pointer) instead
// of this structure. IMO giving it a name is the better option.
struct expensive_handle {
struct expensive * target;
};
// Store the simple data members as usual, store a pointer to a
// handle (pointer) to the expensive ones
struct my_struct {
int simple;
struct expensive_handle * handle;
};
struct expensive {
int content; // whatever
};
创建 my_struct
必须创建用于间接寻址的附加 pointer/handle:
struct my_struct * new() {
struct my_struct * data = malloc(sizeof(*data));
// Error handling please
// Set simple data members
data->handle = malloc(sizeof(*(data->handle)));
// Error handling please
data->handle->target = NULL;
return data;
}
target
成员(一旦计算就会指向昂贵的数据)最初设置为 NULL
。
即使使用 const
合格的 my_struct
,也可以访问(因此可能延迟计算)昂贵的数据成员,因为 my_struct
的数据成员没有更改:
int get_expensive(struct my_struct const * ptr) {
if (ptr->handle->target == NULL) {
ptr->handle->target = malloc(sizeof(struct expensive));
// Error handling please
puts("A hell of a computation just happened!");
ptr->handle->target->content = 42; // WOO
}
return ptr->handle->target->content;
}
唯一改变的是*(ptr->handle)
的数据成员,一个struct expensive_handle
。这不是 const 限定的(只有指向它的名为 handle
的指针是)。
测试(Live on ideone):
int main(void) {
struct my_struct * p = new();
printf("%d\n", get_expensive(p));
printf("%d\n", get_expensive(p));
}
(1) 但是,无法从您的虚拟示例中判断这是合理的还是完全浪费资源(程序员和计算)。
我有这样的 C 结构:
struct my_struct {
int i;
double d;
struct expensive_type * t;
};
此结构的实例已创建并初始化为:
struct my_struct * my_new( int i , double d)
{
struct my_struct * s = malloc( sizeof * s);
s->i = i;
s->d = d;
s->t = NULL;
return s;
}
计算 struct expensive_type * t
成员非常昂贵,可能不需要 - 因此它只是初始化为 NULL
- 然后按需计算:
const struct expensive_type * my_get_expensive( const struct my_struct * s)
{
if (!s->t)
s->t = my_expensive_alloc( s->i , s->d );
return s->t;
}
在 C++ 中,我会在 struct expensive_type *
成员上使用 mutable
,是否有可能在 C 中实现类似的东西,即在本地丢弃常量:
{
struct my_struct * mutable_s = (struct my_struct*) s;
mutable_s->t = ...;
}
或者删除签名中的 const
是我唯一符合标准的选择吗?
您可以(1)重构您的代码并添加一个间接层:
struct expensive; // Forward declaration, ignore
// One could also use a struct expensive * (a pointer) instead
// of this structure. IMO giving it a name is the better option.
struct expensive_handle {
struct expensive * target;
};
// Store the simple data members as usual, store a pointer to a
// handle (pointer) to the expensive ones
struct my_struct {
int simple;
struct expensive_handle * handle;
};
struct expensive {
int content; // whatever
};
创建 my_struct
必须创建用于间接寻址的附加 pointer/handle:
struct my_struct * new() {
struct my_struct * data = malloc(sizeof(*data));
// Error handling please
// Set simple data members
data->handle = malloc(sizeof(*(data->handle)));
// Error handling please
data->handle->target = NULL;
return data;
}
target
成员(一旦计算就会指向昂贵的数据)最初设置为 NULL
。
即使使用 const
合格的 my_struct
,也可以访问(因此可能延迟计算)昂贵的数据成员,因为 my_struct
的数据成员没有更改:
int get_expensive(struct my_struct const * ptr) {
if (ptr->handle->target == NULL) {
ptr->handle->target = malloc(sizeof(struct expensive));
// Error handling please
puts("A hell of a computation just happened!");
ptr->handle->target->content = 42; // WOO
}
return ptr->handle->target->content;
}
唯一改变的是*(ptr->handle)
的数据成员,一个struct expensive_handle
。这不是 const 限定的(只有指向它的名为 handle
的指针是)。
测试(Live on ideone):
int main(void) {
struct my_struct * p = new();
printf("%d\n", get_expensive(p));
printf("%d\n", get_expensive(p));
}
(1) 但是,无法从您的虚拟示例中判断这是合理的还是完全浪费资源(程序员和计算)。