Implementing the sizeof operator

  • Thread starter Abhishek Srivastava
  • Start date
A

Alf P. Steinbach

* Frederick Gotham:
Alf P. Steinbach posted:



I think that applies only if the argument being passed is an R-value:

Yes, and that's what you have with the "=" default argument.

The problem stems from trying to pack too much into one function.

Make it two functions: one that has no argument, and one that has one
argument (no default value).
 
S

Stuart Golodetz

Alf P. Steinbach said:
* Frederick Gotham:

Prefer a template function to a macro. One problem with macros is that
they can easily conflict with language and standard library names. The
above one does, and that's a practical problem, not just a formal one.

Is there any way to preserve the same syntax with a template function
though? With the macro version you can use a type name as the parameter,
i.e. sizeof(int) or whatever (ignoring the fact that sizeof already exists
for the moment), but I can't think how you'd do that with a template
function. Any thoughts?

Also, why are we casting 32 in the above? I can see how it works, but why
the seemingly arbitrary magic number? Am I missing something obvious or
would any number work there? (Is alignment an issue here? Just a thought,
may be nonsense! (It is quite late...))

Cheers :)
Stu
 
F

Frederick Gotham

Stuart Golodetz posted:

Also, why are we casting 32 in the above? I can see how it works, but
why the seemingly arbitrary magic number? Am I missing something obvious
or would any number work there? (Is alignment an issue here? Just a
thought, may be nonsense! (It is quite late...))


I had to hazard a guess as to what would be a valid address on the majority
of platforms. A power of 2 sounded nice.
 
G

gottlobfrege

Stuart said:
Is there any way to preserve the same syntax with a template function
though? With the macro version you can use a type name as the parameter,
i.e. sizeof(int) or whatever (ignoring the fact that sizeof already exists
for the moment), but I can't think how you'd do that with a template
function. Any thoughts?

size_of<T>::value

would be the 'equivalent' template syntax to the macro.
I think the implementation would be:

template <typename T>
struct size_of
{
static const std::size_t value = (std::size_t)(char *)( (T *)0 + 1
); //orsomethinglikethat
};
Also, why are we casting 32 in the above? I can see how it works, but why
the seemingly arbitrary magic number? Am I missing something obvious or
would any number work there? (Is alignment an issue here? Just a thought,
may be nonsense! (It is quite late...))

Some compilers (gcc), on highest warning levels, complain when you cast
0 to a pointer, using 32 instead of 0 makes the macro more complicated,
but removes the warning.

Cheers :)
Stu

- Tony
 
S

Samshayam

A simple macro that computes the size of type:

#define SIZE(type) ((type*)0 +1)

i have verified its credibility for built in types, dont know about
compound types

regards
Sam
 
T

Tom Widmer

Frederick said:
(e-mail address removed) posted:




(1) The first member of a POD has the same address as the POD itself.

(2) There's no padding between array elements.


So alignment isn't a problem.

If you're not allowed to create a temporary, then I think the following
is the closest thing you could have to "sizeof" for a type:

#define sizeof(T) \
(char const *)( ((T) const *)32 + 1 ) \
-(char const *)( ((T) const *)32 ) \

Of course, that isn't legal because you're performing pointer arithmetic
on an invalid pointer value. Also, the result isn't an integral constant
expression, so can't be used as, e.g., an array bound.
If, however, you want the size of an object, or perhaps the size of a
type (but you can use a temporary), then it's trivial:


#include <iostream>
#include <cstddef>

template<class T>
std::size_t SizeOf( T const &obj = T() )
{
return (char const *)(&obj + 1) - (char const *)(&obj);
}

int main()
{
unsigned i;

std::cout << SizeOf(i);

std::cout << SizeOf<unsigned>();
}

Doesn't work for:
1. Non-default constructibles
2. Abstract classes
3. Arrays
4. Other non-copyables
5. References
6. Local types

Here's my version that fixes 1-5, but has other problems (only works up
to a certain type size).

#include <iostream>
#include <cstddef>

std::size_t const biggerThanAnyType = 10000000;
char largeStorage[biggerThanAnyType];
void* const largeStorageP = largeStorage;

template <class T>
struct SizeOf
{
static std::size_t value()
{
return f();
}
private:
static std::size_t f( T const *obj = static_cast<T const*>(largeStorageP))
{
void const* p1 = obj;
void const* p2 = obj + 1;
return static_cast<char const*>(p2) - static_cast<char const*>(p1);
}
};

template <class T, std::size_t N>
struct SizeOf<T[N]>
{
static std::size_t value()
{
return N * SizeOf<T>::value();
}
};

template <class T>
struct SizeOf<T&>
{
static std::size_t value()
{
return SizeOf<T>::value();
}
};

struct Abstract
{
virtual void f() = 0;
};

#define SizeOf(T) (SizeOf<T>::value())

int main()
{
std::cout << SizeOf(int) << '\n';
typedef int array[10][20];
std::cout << SizeOf(array) << '\n';
std::cout << SizeOf(Abstract) << '\n';
std::cout << SizeOf(double&) << '\n';
}

I think it's standards conforming, though I'm happy for someone to pick
it apart.

Tom
 
F

Frederick Gotham

posted:
A simple macro that computes the size of type:

#define SIZE(type) ((type*)0 +1)

i have verified its credibility for built in types, dont know about
compound types


On your own system, perhaps.

It's undefined behaviour as far as the Standard is concerned, because there
is no gurantee that you can increment a null pointer and be left with a valid
address.

For the same reason, "offsetof" is implemented differently on different
platforms.
 
G

gottlobfrege

Frederick said:
posted:



On your own system, perhaps.

It's undefined behaviour as far as the Standard is concerned, because there
is no gurantee that you can increment a null pointer and be left with a valid
address.

For the same reason, "offsetof" is implemented differently on different
platforms.

Actually, maybe using offsetof is the best (standard conforming) way:

template <typename T>
struct size_of
{
struct test
{
T t;
T u;
};

static const int value = offsetof(test, u);
};


Does that always work? Does alignment/packing matter? etc?

Tony
 
F

Frederick Gotham

Tony posted:

template <typename T>
struct size_of
{
struct test
{
T t;
T u;
};

static const int value = offsetof(test, u);
};


I already suggested that, but "offsetof" can't be used for a non-POD.

Consider the following specialisation of the structure:

template<>
struct sizeof<std::string> {

struct test {

std::string t; /* Non-POD */
std::string u; /* Non-POD */

};

size_t const static value = offsetof(test,u);
/* Opps, working with a non-POD! */
};
 
G

Greg

Wrong. struct X { int a,b } is a POD.

No, X is a POD-struct (that is, each of its members is individually a
POD type) but the X struct itself is not a POD type. X is in fact a
compound type.

Greg
 
R

Ron Natalie

Greg said:
No, X is a POD-struct (that is, each of its members is individually a
POD type) but the X struct itself is not a POD type. X is in fact a
compound type.

Greg
Nope, it is a POD. POD structs are PODS.
3.9 of the standard
Arithmetic types (3.9.1), enumeration types, pointer types, and pointer
to member types (3.9.2), and cv-qualified versions of these types
(3.9.3) are collectively called scalar types. Scalar types, POD-struct
types, POD-union types (clause 9), arrays of such types and cv-qualified
versions of these types (3.9.3) are collectively called POD types.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top