473,804 Members | 2,255 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Intrinsic Array as a Container


Inspired by page 219 of Nicolai M. Josuttis's book, I set out to write a
class for an intrinsic array which would behave, to as far an extent as
possible, like a container. Also though, I wanted no overhead whatsoever.

The code I'm about to show below is not finished, it may contain the odd
oversight, bug or error (but at a quick glance it seems OK).

First of all though, I want to show you some macros I've written. The
purpose of the macros is to:

(1) Reduce repetitive typing.
(2) Reduce the possibility for error.

Before you use these macros though, you must a typedef to your class, e.g.:

class SmartPointerOrW hatever {
typedef SmartPointerOrW hatever ThisClass;
};

The first macro, "POST_IN_TERMS_ OF", expands to a definition of a post-
operator which invokes the corresponding pre-operator. Here it is:

#define POST_IN_TERMS_O F(op) \
ThisClass operator op(int) \
{ \
ThisClass const temp(*this); \
op *this; \
return temp; \
}

The second macro, "OP_IN_TERMS_OF ", expands to a definition of an operator
such as +, which works off +=. Here it is:

#define OP_IN_TERMS_OF( op,param_dec,ob j) \
ThisClass operator op(param_dec) const \
{ \
ThisClass temp(*this); \
temp op##= obj; \
return temp; \
}

(I realise that this won't work if "param_dec" were to contain a comma.)

The third macro, "NON_CONST_IN_T ERMS_OF", expands to a definition of a non-
const member function (or member function operator) which calls the const
version. Here it is:

#define NON_CONST_IN_TE RMS_OF(ret,func _dec,call) \
ret func_dec \
{ \
return \
const_cast<ret> ( \
const_cast<This Class const*>(this)-call \
); \
}

(I realise that this won't work if "func_dec" were to contain a comma.)

First of all I'd like to ask, what do you think of these macros? Has anyone
ever done something similar? You can see them in action now below as I
implement "IntrinsicArray ". Before that though, I'm going to implement a
reverse pointer for use as a reverse iterator:

#include <cstddef>

template<class T>
struct ReversePtr {

typedef ReversePtr ThisClass;
typedef std::size_t size_t;

T *p;

ReversePtr(T *const arg) : p(arg) {}

operator T*() { return p; }
operator T const *() const { return p; }

ReversePtr &operator++( ) { --p; return *this; }
ReversePtr &operator--() { ++p; return *this; }

POST_IN_TERMS_O F(++)
POST_IN_TERMS_O F(--)

ReversePtr &operator+=(siz e_t const i) { p -= i; return *this; }
ReversePtr &operator-=(size_t const i) { p += i; return *this; }

OP_IN_TERMS_OF( +,size_t const i,i)
OP_IN_TERMS_OF(-,size_t const i,i)

T const &operator[](size_t const i) const { return *(p-i); }
NON_CONST_IN_TE RMS_OF(T&,opera tor[](size_t const i),operator[](i))
};

What do you think of ReversePtr? I appreciate any suggestions.

Now here's IntrinsicArray:

#include <cstddef>
#include <stdexcept>

template<class T,std::size_t len>
struct IntrinsicArray {

typedef IntrinsicArray ThisClass;

T arr[len];

typedef T value_type;
typedef T *iterator;
typedef T const *const_iterator ;
typedef T &reference;
typedef T const &const_referenc e;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type ;

T const *begin() const { return arr; }
NON_CONST_IN_TE RMS_OF(T*,begin (),begin())

T const *end() const { return arr+len; }
NON_CONST_IN_TE RMS_OF(T*,end() ,end())

ReversePtr<T constrbegin() const { return arr+(len-1); }
NON_CONST_IN_TE RMS_OF(ReverseP tr<T>,rbegin(), rbegin())

ReversePtr<T constrend() const { return arr-1; }
NON_CONST_IN_TE RMS_OF(ReverseP tr<T>,rend(),re nd())

T const &operator[](size_type const i) const {return arr[i];}
NON_CONST_IN_TE RMS_OF(T&,opera tor[](size_type const i),operator[](i))

T const &at(size_typ e const i) const
{
if (i >= len) throw std::range_erro r();
return arr[i];
}
NON_CONST_IN_TE RMS_OF(T&,at(si ze_type const i),at(i))

T const &front() const { return *arr; }
NON_CONST_IN_TE RMS_OF(T&,front (),front())

T const &back() const { return arr[len-1]; }
NON_CONST_IN_TE RMS_OF(T&,back( ),back())

size_type size() const { return len; }
bool empty() const { return false; }
size_type capacity() const { return len; }
size_type max_size() const { return len; }
};

Of course, the code isn't finished yet, but I welcome any comments,
questions, or suggestions.

--

Frederick Gotham
Nov 22 '06
16 1861
Roland Pibinger wrote:
On Fri, 24 Nov 2006 05:57:07 -0500, Kai-Uwe Bux wrote:
>>You seem to think that there is a difference between:

typedef T* iterator;
T* begin() { ... }

and:

typedef T* iterator;
iterator begin() { ... }

But there is none.

Of course there is a difference! When a function returns T* one uses a
T* variable to capture the return value, when a function returns an
iterator an iterator variable is used.
Typedefs introduce aliases. Thus, a variable of type T* and a variable of
type IntrinsicArray< T>::iterator have the same type. The only difference is
in your head, not in the code. You are mistaking the implementation for the
documentation. The docs could (maybe should) state that the return type of
begin() is iterator. The implementation, however, is free to make up to
that promise in any way it pleases.

>>STL-style written client code will always use the
IntrinsicArra y<T>::iterator typedef.

Nope. C/C++ clients can rely on the type of the return value because
that type is part of the function contract.
a) C++ does not support contracts in code. The contract is defined in the
documentation. We have not seen that. I already said that I would specify
iterator in the docs. However, one could, of course, make the guarantee
that iterator = T* part of the specification.

b) If you use the IntrinsicArray< Tas defined, then your code will not
break even if you use T*. Using iterator is still wise and makes your code
easier to change when you want to switch containers. But that's all.
Best

Kai-Uwe Bux
Nov 24 '06 #11

Kai-Uwe Bux wrote:
Roland Pibinger wrote:
On Fri, 24 Nov 2006 05:57:07 -0500, Kai-Uwe Bux wrote:
>You seem to think that there is a difference between:

typedef T* iterator;
T* begin() { ... }

and:

typedef T* iterator;
iterator begin() { ... }

But there is none.
Of course there is a difference! When a function returns T* one uses a
T* variable to capture the return value, when a function returns an
iterator an iterator variable is used.

Typedefs introduce aliases. Thus, a variable of type T* and a variable of
type IntrinsicArray< T>::iterator have the same type. The only difference is
in your head, not in the code.
Of course the difference is only in a human reader's head, but then
that's the only place that matters. There are always countless
different ways to express identical intent to the compiler and the
compiler will cope with all of them equally. Your job as a programmer
is to select, from all those possiblities, the one that most clearly
expresses your intent to a human being.

It is not clear from the first example whether begin() is intended to
return a T* because that is what iterator is typedef'd to be, or
whether begin() is intended to return a T* regardless of what type
iterator is.

In the second example, it is clear that begin() is meant to return an
iterator, whatever type that is.
You are mistaking the implementation for the
documentation. The docs could (maybe should) state that the return type of
begin() is iterator. The implementation, however, is free to make up to
that promise in any way it pleases.
I would argue that, at best, the at-first-glance mistmatch between the
documentation and your first code example needlessly introduces the
risk of confusing the reader for zero gain.

There is the other point that, as the maintainer of the class, if I
need to refactor the class to use a different type for iterator, or
maybe just a different type for a debug build, your first example makes
it harder for me to do that. Not very much harder necessarily,
depending how many function signatures use T* when they mean iterator,
but still needless extra complication for zero gain.

Gavin Deane

Nov 24 '06 #12
Roland Pibinger:
Of course there is a difference! When a function returns T* one uses a
T* variable to capture the return value, when a function returns an
iterator an iterator variable is used.

int Func1() { return 7; }

typedef int MyInt;

MyInt Func2() { return 7; }

int main()
{
int a = Func1();
MyInt b = Func1();

int c = Func2();
MyInt d = Func2();

a = b = c = d;
}

If that doesn't compile, burn your compiler.

--

Frederick Gotham
Nov 24 '06 #13
Gavin Deane:
Of course the difference is only in a human reader's head, but then
that's the only place that matters. There are always countless
different ways to express identical intent to the compiler and the
compiler will cope with all of them equally. Your job as a programmer
is to select, from all those possiblities, the one that most clearly
expresses your intent to a human being.

We will have to simply disagree on this.

I could have written "const_iterator " instead of "T const*", but I prefer the
latter as it's more tangible in my own mind. If you would prefer to write the
former, then fair enough that's your choice.

If I were to write documentation for "IntrinsicArray ", I might choose to list
the function signatures as returning "const_iterator " instead of "T const*".

--

Frederick Gotham
Nov 24 '06 #14
Gavin Deane wrote:
>
Kai-Uwe Bux wrote:
>Roland Pibinger wrote:
On Fri, 24 Nov 2006 05:57:07 -0500, Kai-Uwe Bux wrote:
You seem to think that there is a difference between:

typedef T* iterator;
T* begin() { ... }

and:

typedef T* iterator;
iterator begin() { ... }

But there is none.

Of course there is a difference! When a function returns T* one uses a
T* variable to capture the return value, when a function returns an
iterator an iterator variable is used.

Typedefs introduce aliases. Thus, a variable of type T* and a variable of
type IntrinsicArray< T>::iterator have the same type. The only difference
is in your head, not in the code.

Of course the difference is only in a human reader's head, but then
that's the only place that matters. There are always countless
different ways to express identical intent to the compiler and the
compiler will cope with all of them equally. Your job as a programmer
is to select, from all those possiblities, the one that most clearly
expresses your intent to a human being.
The point is which human being we are talking about. Mr Pibinger, I took it,
was talking about a programmer of client code. Such programmer, in my
opinion, should not have any need to read the code for IntrinsicArray< >;
and there is no promise/contract/intent in the code conveyed to the client
programmer.

I grant you that the two variations of the code are not equivalent in
quality: the difference lies in ease of maintainance. There, you have a
point about conveying intent.

It is not clear from the first example whether begin() is intended to
return a T* because that is what iterator is typedef'd to be, or
whether begin() is intended to return a T* regardless of what type
iterator is.

In the second example, it is clear that begin() is meant to return an
iterator, whatever type that is.
The point where to make clear what begin() is supposed to return, is the
specs/docs for this class, not the code. If I open the header files for my
STL implementation of <vector>, I might find that begin() returns something
of type

whatever_fancy_ iterator_facade < value_type * >

where the standard says that begin() returns iterator. Should I believe the
standard or the header file?

>You are mistaking the implementation for the
documentatio n. The docs could (maybe should) state that the return type
of begin() is iterator. The implementation, however, is free to make up
to that promise in any way it pleases.

I would argue that, at best, the at-first-glance mistmatch between the
documentation and your first code example needlessly introduces the
risk of confusing the reader for zero gain.
True.
There is the other point that, as the maintainer of the class, if I
need to refactor the class to use a different type for iterator, or
maybe just a different type for a debug build, your first example makes
it harder for me to do that. Not very much harder necessarily,
depending how many function signatures use T* when they mean iterator,
but still needless extra complication for zero gain.
Here, you are correct, too. I was not arguing that the two examples are
equal in code quality. I was arguing that they are equivalent in observable
behavior and make the same promisses to any client (namely none since, in
this case, promisses to clients have to be part of the docs/specs).

Best

Kai-Uwe Bux
Nov 24 '06 #15

Frederick Gotham wrote:
Gavin Deane:
Of course the difference is only in a human reader's head, but then
that's the only place that matters. There are always countless
different ways to express identical intent to the compiler and the
compiler will cope with all of them equally. Your job as a programmer
is to select, from all those possiblities, the one that most clearly
expresses your intent to a human being.

We will have to simply disagree on this.
As long as I never have to maintain code you wrote, that approach is
fine by me.
I could have written "const_iterator " instead of "T const*", but I prefer the
latter as it's more tangible in my own mind. If you would prefer to write the
former, then fair enough that's your choice.
The difference to me is that, if, conceptually, the function returns an
object that can be used to iterate through the sequence and can be
used, by dereferencing, to obtain an immutable object in that sequence,
then C++ has a name for such a concept and that name is const_iterator.
The fact that, at the particular point in time you wrote the code, the
underlying type you chose to model the const_iterator concept was a T
const* is incidental. It is an implementation detail. To confuse the
abstract concept with the implementation detail is indicative of a lack
of clarity of thinking.
If I were to write documentation for "IntrinsicArray ", I might choose to list
the function signatures as returning "const_iterator " instead of "T const*".
Then you still introduce the maintenance problem I described.

Gavin Deane

Nov 24 '06 #16

Kai-Uwe Bux wrote:
Gavin Deane wrote:
Kai-Uwe Bux wrote:
Roland Pibinger wrote:
On Fri, 24 Nov 2006 05:57:07 -0500, Kai-Uwe Bux wrote:
You seem to think that there is a difference between:

typedef T* iterator;
T* begin() { ... }

and:

typedef T* iterator;
iterator begin() { ... }

But there is none.
<snip>
Of course the difference is only in a human reader's head, but then
that's the only place that matters. There are always countless
different ways to express identical intent to the compiler and the
compiler will cope with all of them equally. Your job as a programmer
is to select, from all those possiblities, the one that most clearly
expresses your intent to a human being.

The point is which human being we are talking about. Mr Pibinger, I took it,
was talking about a programmer of client code. Such programmer, in my
opinion, should not have any need to read the code for IntrinsicArray< >;
and there is no promise/contract/intent in the code conveyed to the client
programmer.
I was indeed talking about the human being who has to read the code. As
a client of std::vector, I have no more need to be able to comprehend
the code in my <vectorheader than my Grandmother does. I look in my
copy of the standard or my copy of Josuttis to find out what interface
std::vector provides. I don't look in the <vectorheader for that
information because I expect my standard library supplier to implement
the standard correctly or to documnet the instances where they don't
and as long as they do that, I don't care how they do it.

So let me rephrase:
Your job as a programmer is to select, from all those possiblities, the
one that most clearly expresses your intent to the human beings who
need to read your code.
I grant you that the two variations of the code are not equivalent in
quality: the difference lies in ease of maintainance. There, you have a
point about conveying intent.
It is not clear from the first example whether begin() is intended to
return a T* because that is what iterator is typedef'd to be, or
whether begin() is intended to return a T* regardless of what type
iterator is.

In the second example, it is clear that begin() is meant to return an
iterator, whatever type that is.

The point where to make clear what begin() is supposed to return, is the
specs/docs for this class, not the code. If I open the header files for my
STL implementation of <vector>, I might find that begin() returns something
of type

whatever_fancy_ iterator_facade < value_type * >

where the standard says that begin() returns iterator. Should I believe the
standard or the header file?
If you provide me with a class to use, I absolutely agree with you
that, to understand how to use that class I should look in the
documentation you provide, not in the code. If the code does not behave
as documented, the solution is to ask for a refund.

However, I was coming from the perspective of your successor on the
project. If you move on to bigger and brighter things and I pick up
your code and documentation to maintain, it is very important to me
(and therefore to my employer if we assume a professional context) that
your code and documentation are easy to comprehend.

<snip>

Gavin Deane

Nov 25 '06 #17

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
3925
by: Jeremy Cowles | last post by:
I have been reading a book that focuses on understanding the intrinsic types of C++ in depth. The author's mentality is this: "Understand the intrinsic types, then learn the std types as needed later", but I have been reading the stroustrup (spelling?) book and he says that it is much better to learn the standard library first as a beginner, and then worry about the intrinsic types afterwards. So there is no doubt that you need to have a...
9
4815
by: justanotherguy63 | last post by:
Hi, I am designing an application where to preserve the hierachy and for code substitability, I need to pass an array of derived class object in place of an array of base class object. Since I am using vector class(STL), the compiler does not allow me to do this. I do realize there is a pitfall in this approach(size of arrays not matching etc), but I wonder how to get around this problem. I have a class hierachy with abstract base...
29
5488
by: shmartonak | last post by:
For maximum portability what should the type of an array index be? Can any integer type be used safely? Or should I only use an unsigned type? Or what? If I'm using pointers to access array elements as *(mptr+k) where I've declared MYTYPE *mptr; what should be the type of 'k'? Should it be ptrdiff_t?
13
3289
by: Alek Davis | last post by:
Hi, Is it possible to access intrinsic ASP objects, such as Request, from a .NET class. Say, I have a .NET library exposed via a COM or COM+ wrapper. Can this library retrieve the request info (basically, server variables exposed via the Request object), when it is invoked from a traditional ASP (not ASP.NET) application? Any ideas? Thanks in advance. Alek
4
2224
by: bienwell | last post by:
Hi all, Data displayed on the datalist control is bound by the column name of the dataset like this : <%# DataBinder.Eval(Container.DataItem, "title")%> Could I use an element of the array (i.e. index=0) which has the name "title" in place of it ? For example:
6
458
by: Paminu | last post by:
If I have this struct: #include <stdlib.h> #include <stdio.h> #define KIDS 4 typedef struct test { int x; int y; } container;
18
4217
by: toton | last post by:
Hi, In C++ when I initialize an array it, also initializes the class that it contains, which calls the default constructor. However, I want to initialize the array only (i.e reserve the space) and use my specific constructor to initialize the class. How to do it without using malloc? Something like Point* pt = new Point; I want it to reserve the space for N points only, and not to call default constructor. I dont have a default...
4
3444
by: De_Kabal | last post by:
I'm trying to bind a 12x16 array to a repeater to display the information in a table to have certain format. Right now all it does is display all the array elements on individual rows. Does anyone know how to display the data on just the 12 row? thanks; Here is my code: Binding:
7
2106
by: Unite | last post by:
I have a ArrayList which I add a Array to. How will I access the array from the ArrayList? Example : /*Storing the array*/ String Container = new String; ArrayList arr =new ArrayList(); ResultSet rec1 = st.executeQuery("SELECT * FROM HistoryHeader WHERE DocumentDate BETWEEN '"+startDate+"' AND '"+endDate+"'"); while(rec1.next()) { Container = rec1.getString("DocumentType");
0
9594
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
1
10347
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10090
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7635
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6863
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5531
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5673
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3832
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
3001
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.