[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Copy-less initialization of a TR1 array

zr

11/10/2008 12:31:00 PM

Hi,

Is there a way to initialize a std::tr1::array with a pre-allocated
built-in array in a copy-less assignment, such that both will point to
the same memory?
Vice-versa is easy to do, simply use std::t1::array::data() and assign
the returned value to the c-style pointer;

if STL does not support this, is there any other library that has such
a container (maybe BOOST)?

Here is an example of what i have in mind:

#include <array>
using namespace std::tr1;

int main()
{

int cArray[] = { 1 , 2, 3, 4};

array<int,4> tr1Array(cArray); // Using some imaginary c-tor. Don't
want to copy. Want to use preallocated memory

tr1Array[0] = 42;
assert(tr1Array[0] == cArray[0] == 42); // Both point to same memory

tr1Array[100] = 42; //In debug builds, this should raise an exception
cArray[100] = 42; //Much harder to catch

return 0;
}
20 Answers

Maxim Yegorushkin

11/10/2008 1:53:00 PM

0

On Nov 10, 12:30 pm, zr <zvir...@gmail.com> wrote:

> Is there a way to initialize a std::tr1::array with a pre-allocated
> built-in array in a copy-less assignment, such that both will point to
> the same memory?

There is a way. Disclaimer: it is not blessed by the standard.

> Vice-versa is easy to do, simply use std::t1::array::data() and assign
> the returned value to the c-style pointer;
>
> if STL does not support this, is there any other library that has such
> a container (maybe BOOST)?
>
> Here is an example of what i have in mind:
>
> #include <array>
> using namespace std::tr1;
>
> int main()
> {
>
> int cArray[] = { 1 , 2, 3, 4};
>
> array<int,4> tr1Array(cArray); // Using some imaginary c-tor. Don't
> want to copy. Want to use preallocated memory

Here you do:

// make sure that the binary layouts of
// array<> and C-array are the same
typedef int static_assert[sizeof(array<int,4>) == sizeof(cArray) ?
1 : -1];
// now do the hack
array<int,4>& tr1Array = reinterpret_cast<array<int,4>&>(cArray);

> tr1Array[0] = 42;
> assert(tr1Array[0] == cArray[0] == 42); // Both point to same memory
>
> tr1Array[100] = 42; //In debug builds, this should raise an exception
> cArray[100] = 42; //Much harder to catch
>
> return 0;
>
> }

--
Max

zr

11/10/2008 3:10:00 PM

0

On Nov 10, 3:52 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
> On Nov 10, 12:30 pm, zr <zvir...@gmail.com> wrote:
>
> > Is there a way to initialize a std::tr1::array with a pre-allocated
> > built-in array in a copy-less assignment, such that both will point to
> > the same memory?
>
> There is a way. Disclaimer: it is not blessed by the standard.
>
>
>
> > Vice-versa is easy to do, simply use std::t1::array::data() and assign
> > the returned value to the c-style pointer;
>
> > if STL does not support this, is there any other library that has such
> > a container (maybe BOOST)?
>
> > Here is an example of what i have in mind:
>
> > #include <array>
> > using namespace std::tr1;
>
> > int main()
> > {
>
> > int cArray[] = { 1 , 2, 3, 4};
>
> > array<int,4> tr1Array(cArray); // Using some imaginary c-tor. Don't
> > want to copy. Want to use preallocated memory
>
> Here you do:
>
>     // make sure that the binary layouts of
>     // array<> and C-array are the same
>     typedef int static_assert[sizeof(array<int,4>) == sizeof(cArray) ?
> 1 : -1];
>     // now do the hack
>     array<int,4>& tr1Array = reinterpret_cast<array<int,4>&>(cArray);
>
> > tr1Array[0] = 42;
> > assert(tr1Array[0] == cArray[0] == 42); // Both point to same memory
>
> > tr1Array[100] = 42; //In debug builds, this should raise an exception
> > cArray[100] = 42; //Much harder to catch
>
> > return 0;
>
> > }
>
> --
> Max

Thanks, Max. I wonder if there is a similar trick for casting a
dynamic array to a std::vector...

AnonMail2005@gmail.com

11/10/2008 3:20:00 PM

0

On Nov 10, 7:30 am, zr <zvir...@gmail.com> wrote:
> Hi,
>
> Is there a way to initialize a std::tr1::array with a pre-allocated
> built-in array in a copy-less assignment, such that both will point to
> the same memory?
> Vice-versa is easy to do, simply use std::t1::array::data() and assign
> the returned value to the c-style pointer;
>
> if STL does not support this, is there any other library that has such
> a container (maybe BOOST)?
>
> Here is an example of what i have in mind:
>
> #include <array>
> using namespace std::tr1;
>
> int main()
> {
>
> int cArray[] = { 1 , 2, 3, 4};
>
> array<int,4> tr1Array(cArray); // Using some imaginary c-tor. Don't
> want to copy. Want to use preallocated memory
>
> tr1Array[0] = 42;
> assert(tr1Array[0] == cArray[0] == 42); // Both point to same memory
>
> tr1Array[100] = 42; //In debug builds, this should raise an exception
> cArray[100] = 42; //Much harder to catch
>
> return 0;
>
>
>
> }- Hide quoted text -
>
> - Show quoted text -

The issue with doing that is that once you have a container, you
should be able to do whatever you want with it (e.g. changing it's
elements). So unless you put it behind an interface (e.g. a function
or class) that returns a const container, it won't work.

You can use constant built in arrays by passing around a pair of it's
begin and end const iterators. Client code that uses it only knows
that it's a const container and has no knowledge of what kind of
container.

HTH

Victor Bazarov

11/10/2008 3:22:00 PM

0

zr wrote:
> On Nov 10, 3:52 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
> wrote:
>> On Nov 10, 12:30 pm, zr <zvir...@gmail.com> wrote:
>>
>>> Is there a way to initialize a std::tr1::array with a pre-allocated
>>> built-in array in a copy-less assignment, such that both will point to
>>> the same memory?
>> There is a way. Disclaimer: it is not blessed by the standard.
>>
>>
>>
>>> Vice-versa is easy to do, simply use std::t1::array::data() and assign
>>> the returned value to the c-style pointer;
>>> if STL does not support this, is there any other library that has such
>>> a container (maybe BOOST)?
>>> Here is an example of what i have in mind:
>>> #include <array>
>>> using namespace std::tr1;
>>> int main()
>>> {
>>> int cArray[] = { 1 , 2, 3, 4};
>>> array<int,4> tr1Array(cArray); // Using some imaginary c-tor. Don't
>>> want to copy. Want to use preallocated memory
>> Here you do:
>>
>> // make sure that the binary layouts of
>> // array<> and C-array are the same
>> typedef int static_assert[sizeof(array<int,4>) == sizeof(cArray) ?
>> 1 : -1];
>> // now do the hack
>> array<int,4>& tr1Array = reinterpret_cast<array<int,4>&>(cArray);
>>
>>> tr1Array[0] = 42;
>>> assert(tr1Array[0] == cArray[0] == 42); // Both point to same memory
>>> tr1Array[100] = 42; //In debug builds, this should raise an exception
>>> cArray[100] = 42; //Much harder to catch
>>> return 0;
>>> }
>> --
>> Max
>
> Thanks, Max. I wonder if there is a similar trick for casting a
> dynamic array to a std::vector...

Well, yes, by all means. If you don't care about portability, open up
the definition of the 'vector' class, make sure there are no explicit
specialisations for your type, then stuff the data you have into the
struct that has exactly same layout as your 'vector' class, then just
cast the reference to struct to your vector. Just make sure you never
attempt to change the vector, or grow it, or do anything that might
break the fragile state of that Frankenstein monster you're going to put
together. And don't come crying to us when your program doesn't work,
because we won't be able to explain it. It will have *undefined* behaviour.

Come on, give it up and realise that you'll be much better off using the
standard means and worrying about the design at the higher level than
that, and not about the whatever tiny performance improvement you can
squeeze from your program by using such nonsensical approaches. Really.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Vidar Hasfjord

11/10/2008 4:20:00 PM

0

On Nov 10, 12:30 pm, zr <zvir...@gmail.com> wrote:
> Hi,
>
> Is there a way to initialize a std::tr1::array with a pre-allocated
> built-in array in a copy-less assignment, such that both will point to
> the same memory?

Yes, you can use 'placement new':

typedef array <int, 4> A;
int init [] = {1, 2, 3, 4};
A& a = *new (init) A;

Of course, this is equivalent to

array <int, 4> a = {1, 2, 3, 4};

Regards,
Vidar Hasfjord

Maxim Yegorushkin

11/10/2008 4:36:00 PM

0

On Nov 10, 4:20 pm, Vidar Hasfjord <vattilah-gro...@yahoo.co.uk>
wrote:
> On Nov 10, 12:30 pm, zr <zvir...@gmail.com> wrote:
>
> > Hi,
>
> > Is there a way to initialize a std::tr1::array with a pre-allocated
> > built-in array in a copy-less assignment, such that both will point to
> > the same memory?
>
> Yes, you can use 'placement new':
>
>     typedef array <int, 4> A;
>     int init [] = {1, 2, 3, 4};
>     A& a = *new (init) A;

A may overflow init.

> Of course, this is equivalent to
>
>     array <int, 4> a = {1, 2, 3, 4};

Only with POD types. If you replace int with a non-trivial type, this
code will end up calling constructors twice and destructors only once.

--
Max

zr

11/11/2008 8:09:00 AM

0

On Nov 10, 6:35 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
> On Nov 10, 4:20 pm, Vidar Hasfjord <vattilah-gro...@yahoo.co.uk>
> wrote:
>
> > On Nov 10, 12:30 pm, zr <zvir...@gmail.com> wrote:
>
> > > Hi,
>
> > > Is there a way to initialize a std::tr1::array with a pre-allocated
> > > built-in array in a copy-less assignment, such that both will point to
> > > the same memory?
>
> > Yes, you can use 'placement new':
>
> >     typedef array <int, 4> A;
> >     int init [] = {1, 2, 3, 4};
> >     A& a = *new (init) A;
>
> A may overflow init.
>
> > Of course, this is equivalent to
>
> >     array <int, 4> a = {1, 2, 3, 4};
>
> Only with POD types. If you replace int with a non-trivial type, this
> code will end up calling constructors twice and destructors only once.
>
> --
> Max

I had to write a small test to realize the problem, though i don't
understand what is really happening.
Max, or anyone could you please elaborate?

#include <array>
#include <iostream>

using namespace std::tr1;
using namespace std;

class A
{
public:
A():value(10) { cout << "A() c-tor\n"; }
A(const int& _value):value(_value) { cout << "A(const int& _a) c-tor
\n"; }
~A() { cout << "A d-tor\n"; }
int value;
};

int main(int argc, char* argv[])
{
A cArray[] = { 1 , 2, 3, 4};

array<A,4>& tr1Array = *new(cArray) array<A,4>;

for (int i=0; i<4; i++)
cout << cArray[i].value << " ";
cout << endl;
for (int i=0; i<4; i++)
cout << tr1Array[i].value << " ";
cout << endl;

return 0;
}

output:
A(const int& _a) c-tor
A(const int& _a) c-tor
A(const int& _a) c-tor
A(const int& _a) c-tor
A() c-tor
A() c-tor
A() c-tor
A() c-tor
10 10 10 10
10 10 10 10
A d-tor
A d-tor
A d-tor
A d-tor

Maxim Yegorushkin

11/11/2008 9:37:00 AM

0

On Nov 11, 8:09 am, zr <zvir...@gmail.com> wrote:
> On Nov 10, 6:35 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
> wrote:
>
>
>
> > On Nov 10, 4:20 pm, Vidar Hasfjord <vattilah-gro...@yahoo.co.uk>
> > wrote:
>
> > > On Nov 10, 12:30 pm, zr <zvir...@gmail.com> wrote:
>
> > > > Hi,
>
> > > > Is there a way to initialize a std::tr1::array with a pre-allocated
> > > > built-in array in a copy-less assignment, such that both will point to
> > > > the same memory?
>
> > > Yes, you can use 'placement new':
>
> > >     typedef array <int, 4> A;
> > >     int init [] = {1, 2, 3, 4};
> > >     A& a = *new (init) A;
>
> > A may overflow init.
>
> > > Of course, this is equivalent to
>
> > >     array <int, 4> a = {1, 2, 3, 4};
>
> > Only with POD types. If you replace int with a non-trivial type, this
> > code will end up calling constructors twice and destructors only once.
>
> I had to write a small test to realize the problem, though i don't
> understand what is really happening.
> Max, or anyone could you please elaborate?
>
> #include <array>
> #include <iostream>
>
> using namespace std::tr1;
> using namespace std;
>
> class A
> {
> public:
>         A():value(10) { cout << "A() c-tor\n"; }
>         A(const int& _value):value(_value) { cout << "A(const int& _a) c-tor
> \n"; }
>         ~A() { cout << "A d-tor\n"; }
>         int value;
>
> };
>
> int main(int argc, char* argv[])
> {
>         A cArray[] = { 1 , 2, 3, 4};
>
>         array<A,4>& tr1Array = *new(cArray) array<A,4>;
>
>         for (int i=0; i<4; i++)
>                 cout << cArray[i].value << " ";
>         cout << endl;
>         for (int i=0; i<4; i++)
>                 cout << tr1Array[i].value << " ";
>         cout << endl;
>
>         return 0;
>
> }
>
> output:
> A(const int& _a) c-tor
> A(const int& _a) c-tor
> A(const int& _a) c-tor
> A(const int& _a) c-tor
> A() c-tor
> A() c-tor
> A() c-tor
> A() c-tor
> 10 10 10 10
> 10 10 10 10
> A d-tor
> A d-tor
> A d-tor
> A d-tor

Here is a modified version of your code with a bit more insightful
output (I don't have tr1::array thus boost::array is used):

#include <boost/array.hpp>
#include <iostream>

using boost::array;
using namespace std;

struct A
{
A():value(0) { cout << "A@" << static_cast<void*>(this) << "("
<< value << ") c-tor\n"; }
A(int value):value(value) { cout << "A@" <<
static_cast<void*>(this) << "(" << value << ") c-tor\n"; }
~A() { cout << "A@" << static_cast<void*>(this) << "(" <<
value << ") d-tor\n"; }
int value;
};

int main()
{
cout << "constructing cArray\n";
A cArray[] = { 1 , 2, 3, 4};

cout << "constructing array<>\n";
array<A,4>& tr1Array = *new(cArray) array<A,4>;

cout << "destroying cArray\n";
}

This code yields the following output:

constructing cArray
A@0013FF48(1) c-tor
A@0013FF4C(2) c-tor
A@0013FF50(3) c-tor
A@0013FF54(4) c-tor
constructing array<>
A@0013FF48(0) c-tor
A@0013FF4C(0) c-tor
A@0013FF50(0) c-tor
A@0013FF54(0) c-tor
destroying cArray
A@0013FF54(0) d-tor
A@0013FF50(0) d-tor
A@0013FF4C(0) d-tor
A@0013FF48(0) d-tor

As you can see the elements of cArray are overwritten with new(cArray)
array<A,4>. This is because placement new operator treats its cArray
argument as uninitialised memory.

At the end of the scoped the destructors of cArray objects are invoked
(in the reverse order of construction). However, these are not the
original cArray objects.

It is important to understand what happens under the hood of the C++
object model, however, Victor told you the right thing - these are way
too brittle tricks which are bound to wreck havoc in your code sooner
or later.

Is there a reason you can't use tr1::array instead of plain C-style
arrays?

--
Max



zr

11/11/2008 11:34:00 AM

0

On Nov 11, 11:36 am, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
> As you can see the elements of cArray are overwritten with new(cArray)
> array<A,4>. This is because placement new operator treats its cArray
> argument as uninitialised memory.
>
> At the end of the scoped the destructors of cArray objects are invoked
> (in the reverse order of construction). However, these are not the
> original cArray objects.
>
In your example, suppose that i override the default c-tor with one
that does no modification to the object: A() {}, will that solve that
problem? (yes, it may cause other problems, such as uninitialized
objects)

> It is important to understand what happens under the hood of the C++
> object model, however, Victor told you the right thing - these are way
> too brittle tricks which are bound to wreck havoc in your code sooner
> or later.
>
For now, this entire discussion is academic, though hopefully some day
i will find some practical use in it :)

On Nov 11, 11:36 am, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
> Is there a reason you can't use tr1::array instead of plain C-style
> arrays?
Suppose the following example, where the function 'fooReturnsChar8'
returns an array of size 8:
char* a = fooReturnsChar8();
....
i=1;
....
assert(i<8);
a[i] += 7;
....
i=12
....
assert(i<8); // catch bug
a[i] += 5; //bug

It would be very nice to get rid of all the asserts and use an
array<char,8> object for accessing a's data.
fooReturnsChar8 may be called from some external library which i do
not have its source.

Josh Gonik

6/20/2014 11:29:00 PM

0

On Friday, June 20, 2014 4:19:37 PM UTC-7, The Old Man wrote:
> On Friday, June 20, 2014 2:25:56 PM UTC-4, WolfBear wrote:
>
>
>
> > I am not sure that there was a realistic chance of having any of them
>
> > secede except for maybe Bavaria.
>
>
>
> I'd agree, but for the fact that the king had been forced to abdicate and they were having some "problems" with extremist politics.
>
> If the king Ludwig III had been allowed to remain as the head of a constitutional monarchy, or his son Prinz Rupprecht (who lived to 1955 and was very popular with the Bavarian people) and guaranteed a strict neutrality, then MAYBE, but even then, I'm not sure.
>
>
>
> Regards,
>
> John Braungart

Well, the Entente could allow an independent Bavaria to hold a plebiscite in regards to restoring their monarchy (after Bavaria deals with its extremists, of course).