C - 从C++模拟'mutable'

use*_*005 6 c const mutable

我有这样的C结构:

struct my_struct {
   int i;
   double d;
   struct expensive_type * t;
};
Run Code Online (Sandbox Code Playgroud)

创建此结构的实例并将其初始化为:

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;
}   
Run Code Online (Sandbox Code Playgroud)

计算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;  
 }
Run Code Online (Sandbox Code Playgroud)

在C++中,我会用mutable的上的struct expensive_type *成员,是有可能实现用C类似的东西,即本地虚掷的常量:

{
    struct my_struct * mutable_s = (struct my_struct*) s;
    mutable_s->t = ...;
Run Code Online (Sandbox Code Playgroud)

  }

或者const在签名中删除我唯一符合标准的替代方案?

Dan*_*our 2

可以(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
};
Run Code Online (Sandbox Code Playgroud)

创建一个my_struct必须创建用于间接寻址的附加指针/句柄:

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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

唯一改变的是 的数据成员*(ptr->handle)a struct expensive_handle。它不是 const 限定的(只有指向它的指针被命名handle)。

测试(在 ideone 上运行):

int main(void) {
  struct my_struct * p = new();
  printf("%d\n", get_expensive(p));
  printf("%d\n", get_expensive(p));
}
Run Code Online (Sandbox Code Playgroud)

(1) 但是,这是否合理或完全浪费资源(程序员和计算)无法从您的虚拟示例中决定。