Effeciency

D

David Rasmussen

I want to have an unsigned integer-like thing, that for now only allows
the bitwise operators. I have defined these operators and their
self-assigning cousins.

This works, but I would like to know what the most effecient way of
doing this is. Preferably, there should be no overhead compared to a
read unsigned long int. No extra temporaries, full inlining etc. The
same code should be generated.

The only difference between an unsigned long int and my class should be
that it is it's own separate type and that I control what operations and
conversions are possible/automatic.

class MyClass
{
public:
MyClass() {}
explicit MyClass(unsigned long int uli)
{
bb = uli;
}

MyClass& operator &=(const MyClass& rhs) { bb &= rhs.bb; return
*this; }
MyClass& operator |=(const MyClass& rhs) { bb |= rhs.bb; return
*this; }
MyClass& operator ^=(const MyClass& rhs) { bb ^= rhs.bb; return
*this; }

MyClass operator &(const MyClass& rhs) { return MyClass(bb & rhs.bb); }
MyClass operator |(const MyClass& rhs) { return MyClass(bb | rhs.bb); }
MyClass operator ^(const MyClass& rhs) { return MyClass(bb ^ rhs.bb); }

private:
unsigned long int bb;
};

/David
 
A

Alf P. Steinbach

I want to have an unsigned integer-like thing, that for now only allows
the bitwise operators. I have defined these operators and their
self-assigning cousins.

This works, but I would like to know what the most effecient way of
doing this is. Preferably, there should be no overhead compared to a
read unsigned long int. No extra temporaries, full inlining etc. The
same code should be generated.

The only difference between an unsigned long int and my class should be
that it is it's own separate type and that I control what operations and
conversions are possible/automatic.

That is a quality-of-implementation issue.

C++ formally allows the compiler to generate any amount of overhead.

If you can live with somewhat less control over operations it might be
an idea to consider an enum-type as your type (just a thought).
 
G

Gianni Mariani

David said:
I want to have an unsigned integer-like thing, that for now only allows
the bitwise operators. I have defined these operators and their
self-assigning cousins.

This works, but I would like to know what the most effecient way of
doing this is. Preferably, there should be no overhead compared to a
read unsigned long int. No extra temporaries, full inlining etc. The
same code should be generated.

The only difference between an unsigned long int and my class should be
that it is it's own separate type and that I control what operations and
conversions are possible/automatic.

class MyClass
{
public:
MyClass() {}
explicit MyClass(unsigned long int uli)
{
bb = uli;
}

.... knit - best to get into the habbit of using initializer lists
i.e.:
explicit MyClass(unsigned long int uli)
: bb(uli)
{
}

You lack a copy constructor:

MyClass( const MyClass & );

.... and a default constructor

MyClass();

.... an an assignment operator.

MyClass& operator= (const MyClass& rhs);

It's hard to do much without the above functions.

As far as performance goes - the operators below seem fine.
MyClass& operator &=(const MyClass& rhs) { bb &= rhs.bb; return
*this; }
MyClass& operator |=(const MyClass& rhs) { bb |= rhs.bb; return
*this; }
MyClass& operator ^=(const MyClass& rhs) { bb ^= rhs.bb; return
*this; }

This looks about as good as you could as well. The only picky issue is
that you're duplicating the functionality above but you're likely not
going to get any issues here because of that.
 
D

David Rasmussen

Alf said:
That is a quality-of-implementation issue.

I know, but...
C++ formally allows the compiler to generate any amount of overhead.

I know, but...

Maybe I should rephrase it: I want to make sure that I don't make it
unnecesarily inefficient. I want to give the compiler the best working
conditions.
If you can live with somewhat less control over operations it might be
an idea to consider an enum-type as your type (just a thought).

I can't, but thanks for the suggestion :)

/David
 
R

Ron Natalie

Gianni Mariani said:
You lack a copy constructor:

MyClass( const MyClass & );

... and a default constructor

MyClass();

... an an assignment operator.

MyClass& operator= (const MyClass& rhs);

It's hard to do much without the above functions.

The compiler generates the copy-assignment operator and the
copy constructor for him. As lame as his class is, the compiler
generated ones are just fine.

However, the presence of the constructor from unsinged int means
the default constructor is supressed. He probably wants that one.
 
D

David Rasmussen

Ron said:
The compiler generates the copy-assignment operator and the
copy constructor for him. As lame as his class is, the compiler
generated ones are just fine.

My class is lame?

What I am trying to achieve here is something sorely lacking in C++, but
available in other languages, e.g. Ada.

What I really want, is just for the compiler to do some more work, to
distinguish between my class and an int. That is, more typesafety. This
is a compile time thing only. The compiler ensures that for example
operator + isn't used on my class. When the program is ready for
release, all MyClass instances could be replaced with just variables of
the type of the encapsulated integer. This could be done easily with a
typedef.

The effect is that I ensure type safety, and I get the effeciency of the
integer in release builds. But ideally, there shouldn't be any
performance difference between the two. This class is what the language
forces me to do in order to get some very basic type safety done by the
compiler.
However, the presence of the constructor from unsinged int means
the default constructor is supressed. He probably wants that one.

The empty default constructor? Yes.

/David
 
R

Ron Natalie

David Rasmussen said:
My class is lame?

Sorry, I only meant it doesn't do much other than wrap an int. It doesn't manage pointers
or a bunch of other things that would require specialize copy semantics. Perhaps I should
have said "simple" rather than "lame."
What I am trying to achieve here is something sorely lacking in C++, but
available in other languages, e.g. Ada.

C++ isn't Ada. You can spend your time trying to make it so, but you're not
going to be happy in the long run. I'll give you the bad news now. There is no
way your class is going to be as fast as the built-in. Further, it's going to be next
to impossible to make it behave like the standard int.
What I really want, is just for the compiler to do some more work, to
distinguish between my class and an int. That is, more typesafety. This
is a compile time thing only.

You've lost me as to how not having operator+ makes things more typesafe.
 
V

VANNA CHHUM

David Rasmussen said:
My class is lame?

What I am trying to achieve here is something sorely lacking in C++, but
available in other languages, e.g. Ada.

What I really want, is just for the compiler to do some more work, to
distinguish between my class and an int. That is, more typesafety. This
is a compile time thing only. The compiler ensures that for example
operator + isn't used on my class. When the program is ready for
release, all MyClass instances could be replaced with just variables of
the type of the encapsulated integer. This could be done easily with a
typedef.

The effect is that I ensure type safety, and I get the effeciency of the
integer in release builds. But ideally, there shouldn't be any
performance difference between the two. This class is what the language
forces me to do in order to get some very basic type safety done by the
compiler.


The empty default constructor? Yes.

/David

Hi,
If I understand what you are saying...you want to typify integral types at
compile time to enforce more type safety. Then, you want to replace that
check with an actual integral type (via a typedef) for your release mode
(max efficiency).
If that is what you want, then look at the code below (sloppy - but gets
the point across):


#include <iostream>

template <typename Underlying, int MixType>
struct MyClass {
explicit MyClass(Underlying val) : myVal(val) { /* */ };
friend MyClass operator*(const MyClass& m1, const MyClass& m2) {
return(static_cast<MyClass>(m1.myVal * m2.myVal)); }
friend MyClass operator+(const MyClass& m1, const MyClass& m2) {
return(static_cast<MyClass>(m1.myVal + m2.myVal)); }
// etc.

friend std::eek:stream& operator<<(std::eek:stream& os, const MyClass& m) { os
<< m.myVal; return(os); }

private:
Underlying myVal;
};

// Make as many types you want here
typedef MyClass<unsigned long, 1> FirstIntType;
typedef MyClass<unsigned long, 2> SecondIntType;

// Later replace for maximum efficiency
// typedef unsigned long FirstIntType;
// typedef unsigned long SecondIntType;

int main()
{
FirstIntType a(1), b(2);
SecondIntType c(4), d(5);
std::cout << a * b << std::endl; // ok
std::cout << c * d << std::endl; // ok
std::cout << a * c << std::endl; // error ==> can't mix
std::cout << a * 4 << std::endl; // error ==> can't mix
return(0);
}

Good Luck,
Shane
 
D

David Rasmussen

Ron said:
Sorry, I only meant it doesn't do much other than wrap an int. It doesn't manage pointers
or a bunch of other things that would require specialize copy semantics. Perhaps I should
have said "simple" rather than "lame."

Okay :)
C++ isn't Ada.

Sure it isn't, but this is a design-notion so basic that I can't believe
that it isn't supported by the language. Especially with it's "zero
overhead" principle.

The reason Ariane 5 crashed was because two different departments were
using ints to express the concept of length. The problem was that one
department used meters, the other used feet. In Ada, you can define a
derived type of the builint types, that is limited in some way. That is,
you can define an integer type of Feet that is a different type from the
integer type of Meters, and from all other integers. You don't have to,
but you have the choice. You will have no performance hit. The compiler
will just use normal integers (whatever they are on the platform in
question), but at compile-time, the compiler will ensure that you never
assign length in feet to length in meters.

This notion is very basic and comes up in all sorts of designs. We're
just asking the compiler to do some very reasonable type checking.

We can't do this directly in C++ unfortunately. The only way to get a
new type, is to make a class (or an enum, but that is a crippled type
that we have almost no control over). That means, as you say, overhead.
Goodbye zero overhead principle.

You can spend your time trying to make it so, but you're not
going to be happy in the long run.

I don't want C++ to be Ada. But I would like to be able to express very
basic design notions in C++, that the underlying hardware can express
directly and naturally.
I'll give you the bad news now. There is no
way your class is going to be as fast as the built-in. Further, it's going to be next
to impossible to make it behave like the standard int.

Impossible? Why?
You've lost me as to how not having operator+ makes things more typesafe.

I haven't said that. Not having operator+ is something unrelated that
has to do with the type I want. I simply don't need operator+ for my
type. It has nothing to do with type safety.

What _does_ have something to do with type safety is, like the
Feet/Meter example above, that my class although integer-like, could
never be confused with a normal integer. That is a very reasonable
design criteria, and a source of real bugs in my experience. And it
could be so simple to eliminate.

The simplest way to do it would be a new keyword that allowed one to
define a new strong type based on an old one, whether builtin or not. Like:

newtype unsigned long int MyClass;

That's it. Problem solved.

/David
 
D

David Rasmussen

VANNA said:
Hi,
If I understand what you are saying...you want to typify integral types at
compile time to enforce more type safety. Then, you want to replace that
check with an actual integral type (via a typedef) for your release mode
(max efficiency).
If that is what you want, then look at the code below (sloppy - but gets
the point across):

That is very much along the lines of what I wanted! You understand :)

My only problem is that I also want to be able to overload functions
based on my new type, for example the << operator with output streams (I
don't want to have number printed for my type, I want something
different). That works as long as I am using your code or my own. But as
soon as I switch to the builtin long int, I get errors because C++ can't
overload on just typedefs.

But thanks for your suggestion, I will give it a think.

/David
 
A

Attila Feher

David Rasmussen wrote:
[SNIP]
The reason Ariane 5 crashed was because two different departments were
using ints to express the concept of length. The problem was that one
department used meters, the other used feet.

IIRC this is not true. Ariane was the crashed rocket, wasn't it? And that
has crashed because some program was not stopped after it was not in use
anymore, and sent out bad data. The thing which has crashed for the reason
you say was a Mars thing. Was it called Polar Lander?
In Ada, you can define a
derived type of the builint types, that is limited in some way.
[SNIP]

You will need to read Design and Evolution of C++, and you will get answers
to all of your doubts. There are reasons why you cannot inherit from int in
C++.
 
D

David Rasmussen

Attila said:
IIRC this is not true. Ariane was the crashed rocket, wasn't it? And that
has crashed because some program was not stopped after it was not in use
anymore, and sent out bad data. The thing which has crashed for the reason
you say was a Mars thing. Was it called Polar Lander?

Maybe you're right, but the point still stands.
In Ada, you can define a
derived type of the builint types, that is limited in some way.

[SNIP]

You will need to read Design and Evolution of C++, and you will get answers
to all of your doubts. There are reasons why you cannot inherit from int in
C++.

I own that book and have read it. Very interesting read indeed. In some
cases, Bjarne expresses doubt as whether some design decision was the
right one, and where I agree with this doubt. In other cases he makes a
weak defense for not including some very good idea. And some issues he
doesn't adress at all. Most issues he addresses, and in a convincing manner.

I don't think you can find anything in that book about why you can't
have the compiler to that added type checking on types derived from
builtin types. I also doubt very much that you can come up with any good
reasons for leaving it out.

/David
 
J

Jeff Schwab

David said:
That is very much along the lines of what I wanted! You understand :)

My only problem is that I also want to be able to overload functions
based on my new type, for example the << operator with output streams (I
don't want to have number printed for my type, I want something
different). That works as long as I am using your code or my own. But as
soon as I switch to the builtin long int, I get errors because C++ can't
overload on just typedefs.

I believe you want strong typedef's. They're being considered for a
future version of the language.
 
A

Attila Feher

David Rasmussen wrote:
[SNIP]
I own that book and have read it. Very interesting read indeed. In
some cases, Bjarne expresses doubt as whether some design decision
was the right one, and where I agree with this doubt.

I do not recall very strong doubts from that book.
In other cases he makes
a weak defense for not including some very good idea.

"weak defense" I guess you do not need to work anymore on self-confidence,
you can start on modesty and rhetorics. For example if you criticise things
it makes a lot of sense to give at least examples.
And some issues he doesn't adress at all.

So why don't you? With real arguments - of course.
Most issues he addresses, and in a
convincing manner.

Phew. This is reassuring.
I don't think you can find anything in that book about why you can't
have the compiler to that added type checking on types derived from
builtin types.

As I have asked you to find it, I find it interesting how it turned to be my
job anyways. What I can tell you is that I was able to find convincing
arguments of why Bjarne Stroustrup decided on not allowing inheritance from
fundmental types at all. Therefore I find it no surprise that he did not
waste the trees (the paper) to describe why some sort of other things are
not allowed on those types.
I also doubt very much that you can come up with any
good reasons for leaving it out.

I do not need to. At the time todays C++ has been created Bjarne Stroustrup
came up with them. OTOH if you feel that you can come up with a feasible
proposal on how to add those things into the language, and you come up with
use cases supporting the need, and you come up with convincing arguments of
why to do it the way you want it and you make an offical proposal out of it
which *convinces* *me*, I will be more than happy to present it for a straw
vote to the Evolution Working Group in Sydney this spring. But whatever you
propose has to stand the critical eyes of compiler implementers as well as
the finest minds of the industry (I am not talking about me). So be careful
to make it very convincing and possible to implement.

As for the issue itself. My feeling is that it is possible to come up with
a library based solution, which can be feasible on any quality
implementation. So based on that I find it hard to believe that anyone can
justify a core language change - but unlike you, my mind is not closed by a
prejudical decision. Show what you have got, where and how would you change
the language/the standard, what would it effect and why, what use cases
makes it possible etc. I am sure it is not only me, who will be ready to
look at it.
 
D

David Rasmussen

Jeff said:
I believe you want strong typedef's. They're being considered for a
future version of the language.

That's certainly one of the things i want. It would solve a lot problems.

Do have any links to anything describing this consideration?

/David
 
J

Jeff Schwab

David said:
That's certainly one of the things i want. It would solve a lot problems.

Do have any links to anything describing this consideration?

/David


Sorry, I don't know of any off the top of my head. It's a staple issue
in comp.std.c++, though.
 
J

Jeff Schwab

Attila said:
IIRC they are definitely not.

Aha... Well, never mind then. :)


Do you know where I can get more info? (I'm not a big fan of language
extensions in general, so I'm not cyring too hard about this.) I just
tried STW, though, and couldn't find anything relevant.
 
J

Jeff Flinn

David,

David Rasmussen said:
I want to have an unsigned integer-like thing, that for now only allows
the bitwise operators. I have defined these operators and their
self-assigning cousins.

How about:

typedef std::bitset<32> MyClass;

Jeff F
 

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
473,776
Messages
2,569,603
Members
45,196
Latest member
ScottChare

Latest Threads

Top