-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change functions to accept const ptrs to allocators #89
Conversation
Since conceptionally the state of the allocator is changing when it is being used (think about it that it keeps track of the allocated memory) I don't think that it should be |
I know what you mean, but the allocator struct itself only has a pointer to the state though, which is not modified |
I understand that it technically works with |
I disagree. The The contract on a function that takes a const pointer to an allocator is that the allocator struct itself is not changed, not anything and everything it might reference directly or indirectly. Even if it keeps track of the allocated memory, I don't think making the allocator struct const implies that cannot result in changes to the state.
There is no plan (or foreseeable reason) to do that. What using I might have a function which replaces the malloc function on an allocator struct with a new one, that function would need to have a non-const pointer. That's an example where this use of const differentiates two valid use cases, neither of which have to do with the const-ness of the state value itself. |
Still the fact remains that the API design (using |
That's not true, you can always store arbitrary (and mutable) state in the state object. We could simply change the struct rcutils_allocator_state_t {
size_t malloc_call_count;
size_t free_call_count;
void * implementation_specific_data;
} And I will reiterate that there is no reasonably foreseeable requirement or plan to do the above. We can't design our API to allow for any conceivably possible future change. If C were more expressive or this were C++, then I'd agree with you can we could use non-const pointers to allocator's because then we would just make the function points and the state pointer const in the class (setting them only on construction instead). But that's not the case here. |
I suppose we actually could make the members of the allocator type We'd just have to cast away the const when creating the allocators in the first place or use an initializer list (haven't tried the latter). If that works, then I'd be convinced to leave the pointers to the allocators non-cost is the right thing to do. |
The initializer lists do work. @dhood and @dirk-thomas is that an acceptable compromise? Using const pointers (not const values) for the function pointers and state in the allocator struct and then taking non-const pointers to allocators in all function parameters (inverse of this pr)? |
What I mean actually is the initializer list like syntax, I guess it's actually C-specific struct initialization syntax. |
What about passing it like |
Depending on how the const is being used in the struct that sounds better to me. Can you post a snippet with the proposed code (or update the PR)? |
But this doesn't actually matter, because with or without the typedef struct {
int i;
int j;
} rcutils_allocator_t;
void func1(rcutils_allocator_t * const allocator) {
(void) allocator;
// allocator = (rcutils_allocator_t *)0x02; // compiler error
}
void func2(rcutils_allocator_t * allocator) {
allocator = (rcutils_allocator_t *)0x03;
}
int main(void) {
rcutils_allocator_t * allocator = (rcutils_allocator_t *)0x01;
func1(allocator);
// allocator == 0x01 still
func2(allocator);
// allocator == 0x01 even still
}
I'll put together a pull request or iterate with @dhood on it as an option as soon as I have time. |
I've been looking at swapping the struct to store e.g. There are a number of places where we update allocators stored by value, which with that change will give compiler errors e.g. Line 113 in 002c03c
@wjwwood confirmed that we don't want to restrict users from copying allocators; we can swap some instances to store pointers, but there are times when we store by value so they're not tied to the lifetime of the allocator passed in. We concluded that we should not change the struct, but just remove const from the functions and from places like this. I'll work on that. |
Removing const from all of the allocator references will also mean removing const from signatures that take in options structs e.g. The conclusion upon reflection is that we are not opposed to the notion of I'll add documentation to this effect but otherwise we're satisfied with the original approach of this PR. |
I added documentation of the mutable nature of the state even in const-qualified allocators in d36a4d2; open to input on the wording |
In ros2/rcl#212, I wanted to pass a
const rcl_allocator_t *
torepl_str
, but got warnings that the parameter wasn't const.@dirk-thomas and I spoke about that and were concerned that the functions that currently take const ptrs actually should not, because the state of the allocator can change when the allocator's used. We theorised that a warning about modifying a const variable (when
allocate
is called in a function that takesconst rcutils_allocator_t *
) wasn't being generated because of the type erasure in the signature.@wjwwood pointed out that the state is actually stored as a pointer, so it's fair to use const since these functions never reassign the pointer. That's also why it's fair to pass an allocator by value in other places: it will still impact the state of the original allocator (another thing @dirk-thomas and I were concerned about).
Therefore this PR just changes the remaining functions to take a
const rcutils_allocator_t *
since they don't modify the struct, so that it can be called from places likercl_node_init
which is using a const pointer.