#11312 closed Bugs (fixed)
smart_ptr::detail::as_allocator::allocate() adds alignment padding when it's not needed
| Reported by: | Owned by: | Glen Fernandes | |
|---|---|---|---|
| Milestone: | Boost 1.64.0 | Component: | smart_ptr |
| Version: | Boost 1.57.0 | Severity: | Problem |
| Keywords: | Cc: |
Description
smart_ptr::detail::as_allocator::allocate() {
enum {
M = boost::alignment_of<type>::value
}; std::size_t n1 = count * sizeof(value_type); std::size_t n2 = data.size * sizeof(type); std::size_t n3 = n2 + M; CA ca(allocator()); void* p1 = ca.allocate(n1 + n3);
Allocation is for two items of size n1 and n2. Alignment size is added to n2 to create n3 to there is room to align n2 properly.
if n1 % M == 0 then alignment is already fine and the extra M bytes is wasted.
Change History (15)
comment:1 by , 7 years ago
comment:2 by , 7 years ago
| Owner: | changed from to |
|---|
comment:3 by , 7 years ago
pointer allocate(size_type count, const_void_pointer = 0) {
enum {
M = boost::alignment_of<type>::value
};
std::size_t n1 = count * sizeof(value_type);
std::size_t n2 = data.size * sizeof(type);
std::size_t n3 = n2 + M;
CA ca(allocator());
void* p1 = ca.allocate(n1 + n3);
void* p2 = static_cast<char*>(p1) + n1;
(void)boost::alignment::align(M, n2, p2, n3);
*data.result = static_cast<type*>(p2);
return static_cast<value_type*>(p1);
}
I call:
boost::allocate_shared<int[]>(allocator, 4);
Inside allocate() I see this:
n1 == 20 for ms_init_tag
n2 == 16 for the 4 ints
M == 4
n3 == 20
ca.allocate is called with n1+n3 for a total of 40 bytes.
p1 == some_address
p2 == some_address + n1
boost::alignment::align called to fix p2 for 4 byte alignment
p2 is unchanged by align
So we allocated 40 bytes and we are using the first 20 for ms_init and the next 16 for the int[4] and then there are 4 unused bytes that are not affecting our 4 byte alignment requirement.
comment:4 by , 7 years ago
One optimization I could do is instead of adding alignof(type) bytes:
- If
alignof(value_type) >= align(type)then do not add any additional padding. - Else add
alignof(type) - 1bytes for padding.
comment:6 by , 7 years ago
In fact, one step further:
- If alignof(value_type) >= align(type) then do not add any additional padding.
- Else add alignof(type) - alignof(value_type) bytes for padding.
comment:7 by , 7 years ago
CA is allocator<char> and there is no guarantee for p1 to be aligned at anything, regardless of what the alignment of value_type is.
Although I suppose that the code already assumes that p1 is aligned at alignof(value_type) anyway. But this assumption doesn't seem quite correct.
comment:8 by , 7 years ago
Good point. The above math was under the assumption that for any value_type the allocate() function for any given allocator would yield memory that is at least alignof(std::max_align_t) bytes aligned.
It doesn't seem right to make this assumption, and nothing in [allocator.requirements] provides such a guarantee anyway, so I'll update the implementation accordingly.
comment:9 by , 7 years ago
We should probably use ::rebind<type_with_alignment<alignof(value_type)>::type> to allocate, and then the optimization would hold.
comment:10 by , 7 years ago
But type_with_alignment<alignof(value_type)>::type wouldn't have size 1, right? It would have size at least alignof(value_type) bytes and allocate() takes number of objects.
comment:11 by , 7 years ago
Yes, of course. The number of objects would need to be adjusted accordingly.
comment:12 by , 6 years ago
| Version: | Boost 1.57.0 → Boost 1.63.0 |
|---|
comment:13 by , 6 years ago
| Milestone: | To Be Determined → Boost 1.64.0 |
|---|---|
| Resolution: | → fixed |
| Status: | new → closed |
This should be fixed in develop now after I rewrote all of allocate_shared for arrays. It will probably release with 1.65 unless the tests have enough time to cycle for 1.64 and there are no issues.
comment:14 by , 6 years ago
| Milestone: | Boost 1.64.0 → Boost 1.65.0 |
|---|---|
| Version: | Boost 1.63.0 → Boost 1.57.0 |
Will release in 1.64.
comment:15 by , 6 years ago
| Milestone: | Boost 1.65.0 → Boost 1.64.0 |
|---|

I don't see why. We can only depend on the alignment of
p1as being suitable for an object of typevalue_type.n1 % M == 0doesn't seem to give us anything.