Topic: Address (this pointer) of empty base class subobject unspecified?
Author: "Niels Dekker - no reply address" <invalid@this.is.invalid>
Date: Sun, 9 May 2010 14:10:49 CST Raw View
The C++0x FDC, N3092, [intro.object]/6 says: "Unless an object is a
bit-field or a base class subobject of zero size, the address of that
object is the address of the first byte it occupies."
So what about the address of a zero-sized base class subobject? In case
of single inheritance, is it safe to assume that the "this pointer" of
the base class subobject and the "this pointer" of the derived object
point to the very same byte?
For example, the default constructor of the following template class,
zero_initialized<Derived>, is meant to clear the bytes of the derived
object, by doing memset(this, 0, sizeof(Derived)). Is it supposed to
work?
// Doing the Curiously Recurring Template Pattern (CRTP).
template <class Derived> class zero_initialized
{
// Empty base class: no data members.
protected:
zero_initialized(void)
{
std::memset(this, 0, sizeof(Derived));
};
};
Use case: A possible new implementation of boost::value_initialized<T>:
template <class T>
class value_initialized:
private zero_initialized<value_initialized<T> >
{
T m_data;
public:
value_initialized(void) : m_data() {}
T& data(void) { return m_data; }
};
Fernando Cacciola's boost::value_initialized<T> provides a
value-initialized object of type T
<http://www.boost.org/doc/libs/1_43_0/libs/utility/value_init.htm>. Some
compilers need to have the bytes of the object cleared during the
construction of value_initialized<T>, in order to have the object
properly initialized, for any type T. The current implementation does so
by storing the object in an aligned_storage::type data member, and
clearing the data member beforehand. Now it seems to me that the same
effect might be achieved more efficiently by having value_initialized<T>
derived from a class like zero_initialized<value_initialized<T>>.
However, I wonder, is the "this pointer" of such a base class really
specified, when it is zero-sized?
Kind regards,
Niels
--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: David Krauss <potswa@gmail.com>
Date: Thu, 13 May 2010 11:29:06 CST Raw View
On May 9, 3:10 pm, "Niels Dekker - no reply address"
<inva...@this.is.invalid> wrote:
> The C++0x FDC, N3092, [intro.object]/6 says: "Unless an object is a
> bit-field or a base class subobject of zero size, the address of that
> object is the address of the first byte it occupies."
>
> So what about the address of a zero-sized base class subobject? In case
> of single inheritance, is it safe to assume that the "this pointer" of
> the base class subobject and the "this pointer" of the derived object
> point to the very same byte?
I think that particular exclusion is just meant to clarify that an
empty base class truly has zero size.
However, C++03 10/3 and FCD 10/5 say, "The order in which the base
class subobjects are allocated in the most derived object (1.8) is
unspecified."
So, according to the standard, your code doesn't work. Whether the
standard guarantees anything at all about these pointers that don't
really point to anything, aside from use in static_cast, may be up for
debate.
Your particular ABI may re-validate them by specifying layout, though.
Note that GCC has a longstanding bug where empty base classes must be
listed first to qualify for an ABI guarantee of having an
interchangeable pointer. See
http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/C_002b_002b-Dialect-Options.html#C_002b_002b-Dialect-Options,
under -Wabi.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Niels Dekker - no reply address" <invalid@this.is.invalid>
Date: Fri, 14 May 2010 15:47:42 CST Raw View
>> The C++0x FCD, N3092, [intro.object]/6 says: "Unless an object is a
>> bit-field or a base class subobject of zero size, the address of that
>> object is the address of the first byte it occupies."
>>
>> So what about the address of a zero-sized base class subobject? In
>> case of single inheritance, is it safe to assume that the "this
>> of pointer" the base class subobject and the "this pointer" of the
>> derived object point to the very same byte?
David Krauss wrote:
> I think that particular exclusion is just meant to clarify that an
> empty base class truly has zero size.
I'm not sure. If we define an "empty base class" as a base class without
data members, I think the compiler is not /required/ to leave an empty
base class subobject zero-sized. Please correct me if I'm wrong!
> However, C++03 10/3 and FCD 10/5 say, "The order in which the base
> class subobjects are allocated in the most derived object (1.8) is
> unspecified."
My use case only has one base class subobject, so the order doesn't
matter :-)
> So, according to the standard, your code doesn't work. Whether the
> standard guarantees anything at all about these pointers that don't
> really point to anything, aside from use in static_cast, may be up for
> debate.
Thanks. I can easily do static_cast<Derived*>(this), if that makes
things any better...
However, in the meantime, boost::value_initialized<T> author Fernando
Cacciola convinced me that my suggested empty base class isn't
guaranteed to do what I had in mind in a proper way, for a different
reason:
// Doing the Curiously Recurring Template Pattern (CRTP).
template <class Derived> class zero_initialized
{
// Empty base class: no data members.
protected:
zero_initialized(void)
{
std::memset(this, 0, sizeof(Derived));
};
};
This base class was intended to make sure that the data of the derived
class is always initialized. Unfortunately memset(this, 0,
sizeof(Derived)) might erase more than just the data of the derived
object. It might also erase some padding bytes, which might have some
special compiler-specific bit pattern. It might not be allowed to
overwrite those padding bytes. So I think I should give up this approach
anyway...
Kind regards,
Niels
--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: David Krauss <potswa@gmail.com>
Date: Sat, 15 May 2010 20:16:42 CST Raw View
On May 14, 4:47 pm, "Niels Dekker - no reply address"
<inva...@this.is.invalid> wrote:
> >> The C++0x FCD, N3092, [intro.object]/6 says: "Unless an object is a
> >> bit-field or a base class subobject of zero size, the address of that
> >> object is the address of the first byte it occupies."
>
> >> So what about the address of a zero-sized base class subobject? In
> >> case of single inheritance, is it safe to assume that the "this
> >> of pointer" the base class subobject and the "this pointer" of the
> >> derived object point to the very same byte?
> David Krauss wrote:
> > I think that particular exclusion is just meant to clarify that an
> > empty base class truly has zero size.
>
> I'm not sure. If we define an "empty base class" as a base class without
> data members, I think the compiler is not /required/ to leave an empty
> base class subobject zero-sized. Please correct me if I'm wrong!
Sorry, I meant truly *may have* zero size, i.e. no implication that
there exists a first byte.
> > However, C++03 10/3 and FCD 10/5 say, "The order in which the base
> > class subobjects are allocated in the most derived object (1.8) is
> > unspecified."
>
> My use case only has one base class subobject, so the order doesn't
> matter :-)
They aren't unspecified relative to each other, they're unspecified
period. There is nothing in the standard to imply that bases are
supposed to appear before members.
> > So, according to the standard, your code doesn't work. Whether the
> > standard guarantees anything at all about these pointers that don't
> > really point to anything, aside from use in static_cast, may be up for
> > debate.
>
> Thanks. I can easily do static_cast<Derived*>(this), if that makes
> things any better...
>
> However, in the meantime, boost::value_initialized<T> author Fernando
> Cacciola convinced me that my suggested empty base class isn't
> guaranteed to do what I had in mind in a proper way, for a different
> reason:
The issue isn't so much possible significance of padding bytes, it's
the insignificance of zero. NULL pointers aren't guaranteed to consist
of zero bytes (far from it), pointers to members are particularly
unlikely to, etc.
And of course, this trick doesn't work with a vtable pointer. As
vtables are added at the compiler's discretion, no guarantee can be
made about the code. This is similar to the padding argument.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]