Re: allocate memory 'inside' POD
On Wednesday, April 11, 2012 3:35:40 PM UTC-5, Dave Abrahams wrote:
on Wed Apr 11 2012, cppljevans-AT-gmail.com wrote:
On Saturday, April 7, 2012 12:46:32 AM UTC-5, Dave Abrahams wrote:
[snip]
But if that makes you uneasy, consider:
union foo
{
int nVals;
boost::aligned_storage<
sizeof(int),
boost::alignment_of<double>::value
>::type align;
};
now you could treat the memory starting at &x+1 (where x is of type
foo) as an array of doubles:
[snip]
Hi Dave,
IIUC, the purpose of using aligned_storage with the
alignment_of arg is to make sure the union starts at an
alignment suitable for a double. However, since memory
for the nVals and the array of doubles is to be
allocated with new(as shown by the OP):
foo * fooPtr = static_cast<foo *>(::operator new(memToAlloc));
and since new always (IIUC) returns memory allocated
at the maximum alignment, I'm wondering why the aligned_storage
and alignment_of are needed.
It ensures that (fooPtr+1) is aligned appropriately for storing doubles.
--
I had to think a little before I could understand why that
was important:
sizeof(fooImpl<union_align>) == offsetof(fooImpl<struct_array>, vals)
where:
fooImpl<union_align> is the foo you defined, and
fooImpl<struct_array> is the foo define in OP.
What follows is an implementation of these two methods plus a third,
align_offset. However, I didn't really understand some of the
struct_array implementation; hence, that appears different
( in particular, the definition of fooPtrIncrement [which is
defined as a static function instead of variable]).
---{cut here---
//Purpose:
// Test various alternative implementations of code
// from post:
/*
From: Thomas Mang
Newsgroups: comp.lang.c++.moderated
Subject: allocate memory 'inside' POD
Date: Tue, 3 Apr 2012 11:33:40 -0700 (PDT)
*/
#include <cstdlib>
#include <iostream>
#include <ostream>
#include <new>
#include <boost/aligned_storage.hpp>
typedef
double
vals_type
//type of elements in array
;
typedef
int
size_type
//type of size of array
;
enum
impl_enum
//enumeration of various implementations.
{ struct_array
, union_align
, align_offset
};
char const*
impl_names[align_offset+1]=
{ "struct_array"
, "union_align"
, "align_offset"
};
template
< impl_enum ImplEnum
>
struct
alloc_in_pod_impl
;
template
<
>
struct
alloc_in_pod_impl
< struct_array
>
//code based on that from:
/*
From: Thomas Mang
Newsgroups: comp.lang.c++.moderated
Subject: allocate memory 'inside' POD
Date: Tue, 3 Apr 2012 11:33:40 -0700 (PDT)
*/
{
struct foo
{
size_type nVals;
vals_type vals[1]
//Here actually nVals values shall occur.
//This is done below with new expression.
;
};
static
std::size_t const
vals_offset
= offsetof(foo,vals);
static
vals_type*
get_vals(foo&a_foo)
{
return a_foo.vals;
}
static
vals_type const*
get_vals(foo const&a_foo)
{
return a_foo.vals;
}
};//struct_array
template
<
>
struct
alloc_in_pod_impl
< union_align
>
//code based on that from:
/*
From: Dave Abrahams
Newsgroups: comp.lang.c++.moderated
Subject: Re: allocate memory 'inside' POD
Date: Fri, 6 Apr 2012 22:46:32 -0700 (PDT)
*/
{
union foo
{
size_type nVals;
boost::aligned_storage<
sizeof(int),
boost::alignment_of<vals_type>::value
>::type align;
};
static
std::size_t const
vals_offset
= sizeof(foo)
;
static
vals_type*
get_vals(foo&a_foo)
{
return static_cast<vals_type*>(static_cast<void*>(&a_foo+1));
}
static
vals_type const*
get_vals(foo const&a_foo)
{
return static_cast<vals_type const*>(static_cast<void const*>(&a_foo+1));
}
};//union_align
//{The following #include files from:
// https://svn.boost.org/svn/boost/sandbox/variadic_templates
// /boost/composite_storage/alignment
#include <boost/composite_storage/alignment/aligned_offset.hpp>
//}
template
<
>
struct
alloc_in_pod_impl
< align_offset
>
{
struct foo
{
size_type nVals;
};
static
std::size_t const
vals_offset
= boost::composite_storage::alignment::aligned_offset
< sizeof(foo)
, boost::alignment_of<vals_type>::value
>::value
;
static
vals_type*
get_vals(foo&a_foo)
{
void*pv=&a_foo;
char*pc=static_cast<char*>(pv);
return static_cast<vals_type*>(static_cast<void*>(pc+vals_offset));
}
static
vals_type const*
get_vals(foo const&a_foo)
{
void const*pv=&a_foo;
char const*pc=static_cast<char const*>(pv);
return static_cast<vals_type const*>(static_cast<void const*>(pc+vals_offset));
}
};//align_offset
template
< impl_enum ImplEnum
>
struct
alloc_in_pod_test
: alloc_in_pod_impl
< ImplEnum
>
{
typedef
alloc_in_pod_impl
< ImplEnum
>
super_t
;
typedef typename
super_t::foo
foo
;
static
std::size_t
fooPtrIncrement( size_type n_vals)
/**@brief
* Size of structure containing:
* a size_type
* and
* an array of n_vals of vals_type.
*/
{
std::size_t const space=super_t::vals_offset+sizeof(vals_type)*n_vals;
return space;
}
static
foo*
foo_array( size_type n_vals, size_t n_foos)
{
void*mem=::operator new(fooPtrIncrement(n_vals)*n_foos);
return static_cast<foo*>(mem);
}
static
void
print_foo(foo const & Foo)
{
vals_type const*vals=super_t::get_vals(Foo);
for (size_type i = 0; i < Foo.nVals; ++i)
std::cout << vals[i] << " ";
}
static
foo*
next(foo*a_foo)
{
void*pv=a_foo;
char*pc=static_cast<char*>(pv);
pc+=fooPtrIncrement(a_foo->nVals);
pv=pc;
return static_cast<foo*>(pv);
}
static
foo const*
next(foo const*a_foo)
{
void const*pv=a_foo;
char const*pc=static_cast<char const*>(pv);
pc+=fooPtrIncrement(a_foo->nVals);
pv=pc;
return static_cast<foo const*>(pv);
}
static
void
test( size_type nVals, size_type nFoos)
{
std::cout
<<"alloc_in_pod_test<"
<<impl_names[ImplEnum]
<<">::test("
<<nVals<<","
<<nFoos<<"):\n";
std::cout
<<"vals_offset="<<super_t::vals_offset<<"\n";
foo * const fooPtr = foo_array( nVals, nFoos);
// 'create' nFoos foo objects and initialize their values
foo * fooIter = fooPtr;
for(size_type i = 0; i < nFoos; ++i, fooIter=next(fooIter))
{
fooIter->nVals = nVals;
vals_type*vals=super_t::get_vals(*fooIter);
for (size_type j = 0; j < nVals; ++j)
vals[j] = i * 10.0 + j + j / 10.0;
}
// print them
fooIter = fooPtr;
for(size_type i = 0; i < nFoos; ++i, fooIter=next(fooIter))
{
print_foo(*fooIter);
std::cout << std::endl;
}
::operator delete(fooPtr);
}
};
size_type main()
{
size_type nVals = 6; // number of vals_type values per foo object
size_type nFoos = 3; // number of foo objects to be created
alloc_in_pod_test<struct_array>::test(nVals,nFoos);
alloc_in_pod_test<union_align>::test(nVals,nFoos);
alloc_in_pod_test<align_offset>::test(nVals,nFoos);
return 0;
}
---}cut here---
-regards,
Larry
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]