#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) - 1
bytes 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
p1
as being suitable for an object of typevalue_type
.n1 % M == 0
doesn't seem to give us anything.