2017-05-09 36 views
6

我有一个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我唯一符合标准的替代方案?

+3

C中没有'mutable'或任何接近它的东西。 – DyZ

+1

是的,需要删除'const'或遭受UB。不错的帖子。一个好的答案会引用C规范。 – chux

+0

为什么代码需要'my_get_expensive(const struct my_struct * s)'中的'const'?也许这个目标可以用另一种方式来满足? – chux

回答

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 
}; 

创建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; 
} 

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)这是否是合理的或资源完全是浪费(包括编程和计算),不能从您的虚拟实例决定,虽然。

+0

尊敬的下属选民,请解释我的答案的哪些部分应该改进。 –

+0

谢谢 - 在我的(真实的...)案件中,间接的确是值得的! – user422005