By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
431,872 Members | 2,392 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 431,872 IT Pros & Developers. It's quick & easy.

EBCO - why does it require inheritance?

P: n/a
I recently implemented c++0x variants of tuple to take advantage of
ECBO and then implemented unique_ptr using a tuple to hold the pointer
- deleter pair so that sizeof(unique_ptr<int>) == sizeof(int*).

It then came to my attention that its a lot of hoops to jump through
just to take advantage of ECBO. I'm wondering whats preventing
something like :

struct SomeEmptyType {void f(){}};

struct A {
SomeEmptyType t;
int * i;
};

from having a sizeof(int*) and not sizeof(int*) + 1 + padding to align
with next boundary?

I know the standard says that "Complete objects and member subobjects
of class type shall have nonzero size." and "Base class subobjects are
not so constrained." but why? Is there some C-compatibility issue?

I think "A a; reinterpret_cast<SomeEmptyType*>(&a)->f();" could still
be well formed even if t had no storage or is this not possible to do
for compiler implementors?

Aug 15 '07 #1
Share this Question
Share on Google+
4 Replies


P: n/a
jg
On Aug 15, 10:30 am, Chris Fairles <chris.fair...@gmail.comwrote:
just to take advantage of ECBO. I'm wondering whats preventing
something like :

struct SomeEmptyType {void f(){}};

struct A {
SomeEmptyType t;
int * i;

};

from having a sizeof(int*) and not sizeof(int*) + 1 + padding to align
with next boundary?
t is 1 byte and the total is 8 bytes (3 bytes padding). It cannot be
4 bytes.
>
I know the standard says that "Complete objects and member subobjects
of class type shall have nonzero size." and "Base class subobjects are
not so constrained." but why? Is there some C-compatibility issue?
Your example isn't about inheritance (class A : public B {} is). So
the above statement does not apply to your example.
JG

Aug 15 '07 #2

P: n/a
jg wrote:
On Aug 15, 10:30 am, Chris Fairles <chris.fair...@gmail.comwrote:
>just to take advantage of ECBO. I'm wondering whats preventing
something like :

struct SomeEmptyType {void f(){}};

struct A {
SomeEmptyType t;
int * i;

};

from having a sizeof(int*) and not sizeof(int*) + 1 + padding to align
with next boundary?

t is 1 byte and the total is 8 bytes (3 bytes padding). It cannot be
4 bytes.
>I know the standard says that "Complete objects and member subobjects
of class type shall have nonzero size." and "Base class subobjects are
not so constrained." but why? Is there some C-compatibility issue?

I think it has to do with subobjects having unique addresses. Let's
change your example to
struct A {
SomeEmptyType t1;
SomeEmptyType t2;
int *1;
}

Then if we create an object a of type A, we would have to have &a.t1
!= &a.t2, and similarly with member-pointers.

Joe Gottman
Aug 16 '07 #3

P: n/a
Chris Fairles <ch***********@gmail.comwrote in
news:11**********************@g4g2000hsf.googlegro ups.com:
This all came about while implementing unique_ptr for c++0x.

template <class _Tp>
struct default_delete : public unary_function<_Tp*,void{
default_delete() {}
template <class _Updefault_delete(const default_delete<_Up>&) {}
void operator()(_Tp* __ptr) const {
static_assert(sizeof(_Tp) 0, "can't delete pointer to incomplete
type");
delete __ptr;
}
};

template <class _Tp, class _Tp_Deleter = default_delete<_Tp>>
class unique_ptr {
/* ... */

_Tp* __ptr;
_Tp_Deleter __deleter;
};
Given the nature of your deleter's, you can either make the method static like:

template <class _Tp>
struct default_delete : public unary_function<_Tp*,void{
default_delete() {} template <class _Updefault_delete(const default_delete
_Up>&) {}
static void delete(_Tp* __ptr) const {
static_assert(sizeof(_Tp) 0, "can't delete pointer to incomplete
type");
delete __ptr;
}
};

template <class _Tp, class _Tp_Deleter = default_delete<_Tp>>
class unique_ptr {
/* ... */

_Tp* __ptr;
~unique_ptr() { _Tp_Deleter::delete(__ptr); }
};

or you can instatiate it when you need it rather than at construction time.

template <class _Tp, class _Tp_Deleter = default_delete<_Tp>>
class unique_ptr {
/* ... */

_Tp* __ptr;
~unique_ptr() { _Tp_Deleter()(__ptr); }
};
Just some thoughts,
joe
Aug 22 '07 #4

P: n/a
On Aug 22, 8:17 am, Joe Greer <jgr...@doubletake.comwrote:
Chris Fairles <chris.fair...@gmail.comwrote innews:11**********************@g4g2000hsf.googleg roups.com:
This all came about while implementing unique_ptr for c++0x.
template <class _Tp>
struct default_delete : public unary_function<_Tp*,void{
default_delete() {}
template <class _Updefault_delete(const default_delete<_Up>&) {}
void operator()(_Tp* __ptr) const {
static_assert(sizeof(_Tp) 0, "can't delete pointer to incomplete
type");
delete __ptr;
}
};
template <class _Tp, class _Tp_Deleter = default_delete<_Tp>>
class unique_ptr {
/* ... */
_Tp* __ptr;
_Tp_Deleter __deleter;
};

Given the nature of your deleter's, you can either make the method static like:

template <class _Tp>
struct default_delete : public unary_function<_Tp*,void{
default_delete() {} template <class _Updefault_delete(const default_delete
_Up>&) {}
static void delete(_Tp* __ptr) const {
static_assert(sizeof(_Tp) 0, "can't delete pointer to incomplete
type");
delete __ptr;
}
};

template <class _Tp, class _Tp_Deleter = default_delete<_Tp>>
class unique_ptr {
/* ... */

_Tp* __ptr;
~unique_ptr() { _Tp_Deleter::delete(__ptr); }
};
A good idea, but I don't think this will work when considering user-
defined deleters. It would require deleters to have a static function
but the standard allows the deleter to have non-static state that can
be accessed within the member func (operator or not) that does the
delete.
or you can instatiate it when you need it rather than at construction time.

template <class _Tp, class _Tp_Deleter = default_delete<_Tp>>
class unique_ptr {
/* ... */

_Tp* __ptr;
~unique_ptr() { _Tp_Deleter()(__ptr); }
};
Again, due to deleters having state, and unique_ptr's being able to
store references to deleters, the following is well formed:

struct deleter
{
deleter(std::string msg):m(msg){}
void operator()(int *) {std::cout << msg; delete i;}
std::string m;
};
deleter d("hi mom");
std::unique_ptr<int,deleter&>(new int, d);
//or std::unique_ptr<int,deleter>(new int, deleter("hi mom")) etc.

So instantiation-on-use won't work so long as the above is allowed.
Just some thoughts,
Much appreciated.

Chris

Sep 8 '07 #5

This discussion thread is closed

Replies have been disabled for this discussion.