Topic: Placement new with a constant pointer.
Author: Victor Bazarov <v.Abazarov@comAcast.net>
Date: Tue, 13 Dec 2005 23:55:27 CST Raw View
Hello,
I was recently fiddling with some template operations requiring
eventually a couple of placement new operations, and discovered
that there was no straightforward way to use a pointer to const
object as the placement new "address" (or 'ptr' as it is named
in the Standard, see 18.4.1.3). Since the operators intentionally
perform no action, shouldn't this be allowed:
#include <memory>
struct S { double d; }; // POD
struct U { S s; }; // wrapper, also POD
template<size_t N> void foo(S const (*ptr)[N])
{
const U* wrapper = new (ptr) U[N]; // *****
}
// pulling through a bunch of other functions that require
// the arguments to be references to const arrays of S
// (references to arrays of const S)
void bar(S const (&arr)[10])
{
foo(&arr);
}
?
The line marked with asterisks should work OK if there is no padding
in 'U' (IOW, if the sizeof(S) == sizeof(U)), right? There is no
standard conversion, though, between 'T const*' and 'void*', so the
regular placement new fails to compile.
Would it make sense to add a const (or cv-qualified) version of the
'placement new' operators? Or am I full of misunderstanding? We could
specify that if the constructor invoked by the placement new does
something to the memory, the behaviour is undefined, of course...
Thanks!
Victor
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Wed, 14 Dec 2005 06:48:19 GMT Raw View
* Victor Bazarov:
>
> I was recently fiddling with some template operations requiring
> eventually a couple of placement new operations, and discovered
> that there was no straightforward way to use a pointer to const
> object as the placement new "address" (or 'ptr' as it is named
> in the Standard, see 18.4.1.3). Since the operators intentionally
> perform no action, shouldn't this be allowed:
>
> #include <memory>
>
> struct S { double d; }; // POD
> struct U { S s; }; // wrapper, also POD
>
> template<size_t N> void foo(S const (*ptr)[N])
> {
> const U* wrapper = new (ptr) U[N]; // *****
> }
'prt' is a pointer to the first of possibly many arrays, each of size N.
Presumably you mean
S const* const psArray = *ptr;
U const* const puArray = reinterpret_cast<U const*>( psArray );
This reinterpret_cast is allowed per 9.2/17 (casting to or from pointer to
first member of POD), which is in conflict with 5.2/7, but no matter... ;-)
>
> // pulling through a bunch of other functions that require
> // the arguments to be references to const arrays of S
> // (references to arrays of const S)
> void bar(S const (&arr)[10])
> {
> foo(&arr);
> }
>
> ?
>
> The line marked with asterisks should work OK if there is no padding
> in 'U' (IOW, if the sizeof(S) == sizeof(U)), right? There is no
> standard conversion, though, between 'T const*' and 'void*', so the
> regular placement new fails to compile.
And a good thing is that, IMHO.
> Would it make sense to add a const (or cv-qualified) version of the
> 'placement new' operators? Or am I full of misunderstanding? We could
> specify that if the constructor invoked by the placement new does
> something to the memory, the behaviour is undefined, of course...
I think you shouldn't use placement new to do casting; IMO that's what the
cast operators are for.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Wed, 14 Dec 2005 06:47:43 GMT Raw View
* Victor Bazarov:
>
> struct S { double d; }; // POD
> struct U { S s; }; // wrapper, also POD
Is U guaranteed to be the same size as S?
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: v.Abazarov@comAcast.net (Victor Bazarov)
Date: Wed, 14 Dec 2005 15:33:10 GMT Raw View
Alf P. Steinbach wrote:
> [...]
> I think you shouldn't use placement new to do casting; IMO that's what the
> cast operators are for.
I don't. It may seem so, but in fact I do want those things constructed.
Generally speaking, if the class has user-defined c-tors, it's not a POD
class any more. My question is, so what? What if the c-tor has some
other side effect, like counting instances or registration of some kind?
I need a constant object to be constructed from a constant storage. We
do not use reinterpret_cast for that. We need 'placement new'. Comments?
V
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Wed, 14 Dec 2005 22:09:48 GMT Raw View
* Victor Bazarov:
> Alf P. Steinbach wrote:
> > [...]
> > I think you shouldn't use placement new to do casting; IMO that's what the
> > cast operators are for.
>
> I don't. It may seem so, but in fact I do want those things constructed.
>
> Generally speaking, if the class has user-defined c-tors, it's not a POD
> class any more. My question is, so what? What if the c-tor has some
> other side effect, like counting instances or registration of some kind?
> I need a constant object to be constructed from a constant storage. We
> do not use reinterpret_cast for that. We need 'placement new'. Comments?
It seems to me what you (should) want is the flyweight pattern, not a
language feature -- is that a possible solution?
But while we're at it -- hammering on const -- does anyone have any good
ideas concerning how to avoid redundant coding of member functions like
T& foo();
T const& foo() const; // const version, otherwise same as previous.
E.g., is there a proposal somewhere, perhaps?
Cheers,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: f.fracassi@gmx.net (Fabio Fracassi)
Date: Thu, 15 Dec 2005 15:23:26 GMT Raw View
Alf P. Steinbach wrote:
> But while we're at it -- hammering on const -- does anyone have any
> good ideas concerning how to avoid redundant coding of member functions
> like
>
> T& foo();
> T const& foo() const; // const version, otherwise same as previous.
>
Yes, that would be interesting. But I think if such a thing were to be
proposed it should also cover the redundant coding of const and non-const
handlers, like iterator <-> const_iterator.
I am thinking of something along the lines of "const?" and "mutable?", like:
(Only as an idea, not a proposal. I haven't thought out all implications.)
struct example {
typedef T const? & return_type;
T const?& foo() const?;
private:
const? T handle;
mutable? int count;
}
so if you use it in a non const way:
.
example a;
example::return_type t = a.foo();
it evaluates as:
struct example {
typedef T& return_type;
T& foo();
private:
T handle;
int count;
}
or if used in a const qualified way:
const example a;
(const example)::return_type t = a.foo();
struct example {
typedef T const & return_type;
T const& foo() const;
private:
const T handle;
mutable int count;
}
> E.g., is there a proposal somewhere, perhaps?
I haven't seen one, but I would be very interested.
Fabio
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Me" <anti_spam_email2003@yahoo.com>
Date: Thu, 15 Dec 2005 23:59:38 CST Raw View
Alf P. Steinbach wrote:
> * Victor Bazarov:
> > Alf P. Steinbach wrote:
> > > [...]
> > > I think you shouldn't use placement new to do casting; IMO that's what the
> > > cast operators are for.
> >
> > I don't. It may seem so, but in fact I do want those things constructed.
> >
> > Generally speaking, if the class has user-defined c-tors, it's not a POD
> > class any more. My question is, so what? What if the c-tor has some
> > other side effect, like counting instances or registration of some kind?
> > I need a constant object to be constructed from a constant storage. We
> > do not use reinterpret_cast for that. We need 'placement new'. Comments?
>
> It seems to me what you (should) want is the flyweight pattern, not a
> language feature -- is that a possible solution?
>
> But while we're at it -- hammering on const -- does anyone have any good
> ideas concerning how to avoid redundant coding of member functions like
>
> T& foo();
> T const& foo() const; // const version, otherwise same as previous.
>
> E.g., is there a proposal somewhere, perhaps?
There was a proposal somewhere (that I can't find) that proposed that
the "this" keyword be used as the return type of member functions.
Since I can't find it (and the paper was light on semantics anyway),
this is how it might behave:
struct T {
this & foo() const;
};
struct D : T {
};
T t;
const T ct;
D d;
some_ptr_wrapper<T> spw;
t.foo(); // returns T &
ct.foo(); // returns const T &
d.foo(); // returns D &
// this is a stretch, but it would be nice to have:
spw->foo(); // returns some_ptr_wrapper<T> &
It's unfortunately a 90% solution that only handles chaining of "return
*this" nicely.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: blackhole@spamguard.com ("Gene Bushuyev")
Date: Fri, 16 Dec 2005 05:59:52 GMT Raw View
"Alf P. Steinbach" <alfps@start.no> wrote in message
news:43a0630c.90194109@news.individual.net...
>* Victor Bazarov:
>> Alf P. Steinbach wrote:
>> > [...]
>> > I think you shouldn't use placement new to do casting; IMO that's what
>> > the
>> > cast operators are for.
>>
>> I don't. It may seem so, but in fact I do want those things constructed.
>>
>> Generally speaking, if the class has user-defined c-tors, it's not a POD
>> class any more. My question is, so what? What if the c-tor has some
>> other side effect, like counting instances or registration of some kind?
>> I need a constant object to be constructed from a constant storage. We
>> do not use reinterpret_cast for that. We need 'placement new'.
>> Comments?
>
> It seems to me what you (should) want is the flyweight pattern, not a
> language feature -- is that a possible solution?
>
> But while we're at it -- hammering on const -- does anyone have any
> good
> ideas concerning how to avoid redundant coding of member functions like
>
> T& foo();
> T const& foo() const; // const version, otherwise same as previous.
>
> E.g., is there a proposal somewhere, perhaps?
You mean you need a change in the standard to solve this problem?
You can move common functionality into a separate function. For example,
// 1: create traits to return correct reference
template<class A>
struct RefTrait
{
typedef typename A::reference reference;
};
template<class A>
struct RefTrait<const A>
{
typedef typename A::const_reference reference;
};
template<class T>
class A
{
// 2: common implementation
template<class A> friend
typename RefTrait<A>::reference common(A& a)
{
return a.t;
}
T t;
public:
A();
typedef T& reference;
typedef const T& const_reference;
reference foo() { return common(*this); }
const_reference foo() const { return common(*this); }
};
void test()
{
A<int> a;
const A<int> ac;
int& i = a.foo(); // calls nonconst version
int ic = ac.foo(); // calls const version
}
-- Gene Bushuyev
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Fri, 16 Dec 2005 12:32:31 GMT Raw View
* Gene Bushuyev:
> * Alf P. Steinbach
> >
> > But while we're at it -- hammering on const -- does anyone have any
> > good ideas concerning how to avoid redundant coding of member functions
> > like
> >
> > T& foo();
> > T const& foo() const; // const version, otherwise same as previous.
> >
> > E.g., is there a proposal somewhere, perhaps?
>
> You mean you need a change in the standard to solve this problem?
> You can move common functionality into a separate function. For example,
>
> // 1: create traits to return correct reference
> template<class A>
> struct RefTrait
> {
> typedef typename A::reference reference;
> };
>
> template<class A>
> struct RefTrait<const A>
> {
> typedef typename A::const_reference reference;
> };
>
> template<class T>
> class A
> {
>
> // 2: common implementation
> template<class A> friend
> typename RefTrait<A>::reference common(A& a)
> {
> return a.t;
> }
>
> T t;
>
> public:
> A();
> typedef T& reference;
> typedef const T& const_reference;
>
> reference foo() { return common(*this); }
> const_reference foo() const { return common(*this); }
> };
>
> void test()
> {
> A<int> a;
> const A<int> ac;
> int& i = a.foo(); // calls nonconst version
> int ic = ac.foo(); // calls const version
> }
How does this work for more than one pair of const/non-const function?
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: spam@spamguard.com ("Gene Bushuyev")
Date: Sat, 17 Dec 2005 04:14:24 GMT Raw View
"Alf P. Steinbach" <alfps@start.no> wrote in message
news:43a25b9d.219363187@news.individual.net...
[...]
>
> How does this work for more than one pair of const/non-const function?
Why would that be any different? Introduce another common function for another
pair:
template<class T>
class A
{
// another common implementation
template<class A> friend
typename RefTrait<A>::reference common1(A& a)
{
return a.t * a.t;
}
.
reference foo1() { return common1(*this); }
const_reference foo1() const { return common1(*this); }
};
-- Gene Bushuyev
----------------------------------------------------------------
There is no greatness where there is no simplicity, goodness and truth. ~ Leo
Tolstoy
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Sat, 17 Dec 2005 17:58:44 CST Raw View
* "Gene Bushuyev":
> "Alf P. Steinbach" <alfps@start.no> wrote in message
> news:43a25b9d.219363187@news.individual.net...
> [...]
> >
> > How does this work for more than one pair of const/non-const function?
>
> Why would that be any different? Introduce another common function for another
> pair:
>
> template<class T>
> class A
> {
>
> // another common implementation
> template<class A> friend
> typename RefTrait<A>::reference common1(A& a)
> {
> return a.t * a.t;
> }
> .
> reference foo1() { return common1(*this); }
> const_reference foo1() const { return common1(*this); }
> };
Uh... Yes, that would solve, with some costs,
T& foo();
T const& foo() const;
T& bar();
T const& bar() const;
but I don't think it happens often that foo and bar have the same result
type.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Gene Bushuyev" <spam@spamguard.com>
Date: Sat, 17 Dec 2005 23:27:46 CST Raw View
"Alf P. Steinbach" <alfps@start.no> wrote in message
news:43a3ce72.314295781@news.individual.net...
>* "Gene Bushuyev":
[...]
> Uh... Yes, that would solve, with some costs,
>
> T& foo();
> T const& foo() const;
>
> T& bar();
> T const& bar() const;
>
> but I don't think it happens often that foo and bar have the same result
> type.
Still, what's the problem? Add all types that are necessary into the traits
classes. You can probably have just one pair of traits classes for everything
else in the project. That's not difficult to do.
Alternatively, you can explicitly specify the return types and you won't need
traits. E.g.,
template<class Ret, class A> Ret common_foo(A& a);
template<class Ret, class A> Ret common_bar(A& a);
template<class T, class V>
class A
{
template<class Ret, class A> friend
Ret common_foo(A& a)
{
return a.t;
}
template<class Ret, class A> friend
Ret common_bar(A& a)
{
return a.v;
}
T t;
V v;
public:
A();
T& foo() { return common_foo<T&>(*this); }
const T& foo() const { return common_foo<const T&>(*this); }
V& bar() { return common_bar<V&>(*this); }
const V& bar() const { return common_bar<const V&>(*this); }
};
-- Gene Bushuyev
----------------------------------------------------------------
There is no greatness where there is no simplicity, goodness and truth. ~ Leo
Tolstoy
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: alfps@start.no (Alf P. Steinbach)
Date: Sun, 18 Dec 2005 10:19:34 CST Raw View
* Gene Bushuyev:
> "Alf P. Steinbach" <alfps@start.no> wrote in message
> news:43a3ce72.314295781@news.individual.net...
> >* "Gene Bushuyev":
> [...]
> > Uh... Yes, that would solve, with some costs,
> >
> > T& foo();
> > T const& foo() const;
> >
> > T& bar();
> > T const& bar() const;
> >
> > but I don't think it happens often that foo and bar have the same result
> > type.
>
>
> Still, what's the problem? Add all types that are necessary into the traits
> classes. You can probably have just one pair of traits classes for everything
> else in the project. That's not difficult to do.
But AFAICS yields non-descriptive names like T1, T2 and so on...
> Alternatively, you can explicitly specify the return types and you won't need
> traits. E.g.,
>
> template<class Ret, class A> Ret common_foo(A& a);
> template<class Ret, class A> Ret common_bar(A& a);
>
> template<class T, class V>
> class A
> {
> template<class Ret, class A> friend
> Ret common_foo(A& a)
> {
> return a.t;
> }
> template<class Ret, class A> friend
> Ret common_bar(A& a)
> {
> return a.v;
> }
>
> T t;
> V v;
>
> public:
> A();
>
> T& foo() { return common_foo<T&>(*this); }
> const T& foo() const { return common_foo<const T&>(*this); }
>
> V& bar() { return common_bar<V&>(*this); }
> const V& bar() const { return common_bar<const V&>(*this); }
> };
I think the above can be an in-practice approach.
One potential problem is pollution of the namespace the class occurs in,
which perhaps can be fixed at the cost of introducing an extra nested
namespace for the friend functions to reside in (more code).
Another potential problem is that, as you implicitly point out above, those
friend functions do not respect ordinary access restrictions, i.e. will be
accessible to the client code, because Mr. Andrew rules:
#include <iostream>
#include <ostream>
class A
{
private:
friend void foo( A const& )
{
std::cout << "Andrew" << std::endl;
}
};
class B: public A {};
int main()
{
foo( B() ); // Oops, allowed.
}
A third problem is that it's a teeny tiny little bit fragile, relying on the
programmer to specify things redundantly in a correct way.
There is of course also the "solution" of casting away constness internally
or using mutable or using a pointer to do that job, but the problem to be
solved is to keep the compiler's constness checking.
I don't know whether what I've mentioned above, plus the general need for
writing two argument-forwarders no matter which solution is employed, is
enough to ask for a language feature, but I'd sure like to see one!
Cheers,
- Alf (who's now mostly away, no network access, till January)
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]