473,756 Members | 5,156 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Traversing members of a class with a pointer

While looking at some old code I ran across a snippet that
increments a pointer to access different members of a structure:
....

struct Badness {
std::string m_begin;
std::string m_param1;
std::string m_param2;
std::string m_end;

Badness();
};
....
Badness badness;

std::string *it = &badness.m_begi n;

for (++it; it != &badness.m_e nd; ++it) {
std::cout << it->c_str() << std::endl;
}

It just looks wrong. It depends on all of the members of class
or structure to be consistent so its bad from a maintenance
standpoint. It seems evil to use a pointer beyond the specific
object for which it is defined.

Looking wrong and evil, though, are not rational arguments that
would allow me to convince my technical lead that this code
needs to be changed sooner than later.

Anyone have good talking points?

/Glen
Dec 9 '06 #1
14 1881
Glen Dayton wrote:
While looking at some old code I ran across a snippet that
increments a pointer to access different members of a structure:
...

struct Badness {
std::string m_begin;
std::string m_param1;
std::string m_param2;
std::string m_end;

Badness();
};
...
Badness badness;

std::string *it = &badness.m_begi n;

for (++it; it != &badness.m_e nd; ++it) {
std::cout << it->c_str() << std::endl;
}

It just looks wrong. It depends on all of the members of class
or structure to be consistent so its bad from a maintenance
standpoint. It seems evil to use a pointer beyond the specific
object for which it is defined.

Looking wrong and evil, though, are not rational arguments that
would allow me to convince my technical lead that this code
needs to be changed sooner than later.

Anyone have good talking points?
What about the undefined behavior that the code has; does that count?
Best

Kai-Uwe Bux
Dec 9 '06 #2
Glen Dayton wrote:
>
Looking wrong and evil, though, are not rational arguments that would
allow me to convince my technical lead that this code needs to be
changed sooner than later.
If it works, it works. The behavior isn't defined by the C++ standard,
but I haven't run into a compiler where it won't do just what it ooks
like it does.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
Dec 10 '06 #3
Pete Becker wrote:
Glen Dayton wrote:
>>
Looking wrong and evil, though, are not rational arguments that would
allow me to convince my technical lead that this code needs to be
changed sooner than later.

If it works, it works. The behavior isn't defined by the C++ standard,
but I haven't run into a compiler where it won't do just what it ooks
like it does.
That it is undefined by the standard is one problem. It means
at a future date the code will stop working. That it works is
another part of the problem, because it removes a motivation for
removing a time bomb from the code. In the real-life code from
which this example was taken, macros obscured the class
beginning and end with their m_begin and m_end guards. The code
maintainer needed to add a bool and an int field to the class,
which would've broken the code if maintainer had not first
carefully analyzed it or just had good luck in realizing what
was happening. The next programmer to touch that code may not
be so lucky or smart.

I'll search the standard for a relevant reference, then I'll
write a unit test and refactor this sucker.

Because the compiler knows all the offsets of the members, is
there any chance a near future version of C++ will offer
iterators to access the typeinfo structures and offsets of each
member of a class?

/Glen

Dec 10 '06 #4
Glen Dayton wrote:
While looking at some old code I ran across a snippet that increments a
pointer to access different members of a structure:
...

struct Badness {
std::string m_begin;
std::string m_param1;
std::string m_param2;
std::string m_end;

Badness();
};
...
Badness badness;

std::string *it = &badness.m_begi n;

for (++it; it != &badness.m_e nd; ++it) {
std::cout << it->c_str() << std::endl;
}
I think if you want to avoid UB, you're toast, unless you want to use
pointers to members. Maybe something like this? Note: m_members should
probably be some sort of static.

struct Badness {
std::string m_begin;
std::string m_param1;
std::string m_param2;
std::string m_end;

typedef std::vector<std ::string Badness::*membe r_vec_t;
member_vec_t m_members;
Badness()
{
m_members.push_ back(&Badness:: m_begin);
m_members.push_ back(&Badness:: m_param1);
m_members.push_ back(&Badness:: m_param2);
m_members.push_ back(&Badness:: m_end);
}

};
// ...
Badness badness;
for (Badness::membe r_vec_t it = badness.m_membe rs.begin();
it != badness.m_membe rs.end();
++it)
std::cout << badness.*(*it) << std::endl;
Dec 10 '06 #5
Glen Dayton wrote:
Pete Becker wrote:
>Glen Dayton wrote:
>>>
Looking wrong and evil, though, are not rational arguments that would
allow me to convince my technical lead that this code needs to be
changed sooner than later.

If it works, it works. The behavior isn't defined by the C++ standard,
but I haven't run into a compiler where it won't do just what it ooks
like it does.

That it is undefined by the standard is one problem. It means at a
future date the code will stop working.
No, it means that at a future date the code might stop working. That's
not to say that it's a good way to write code, but hyperventilatin g is
not a good way to start a design.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
Dec 10 '06 #6

Pete Becker wrote:
Glen Dayton wrote:
Pete Becker wrote:
If it works, it works. The behavior isn't defined by the C++ standard,
but I haven't run into a compiler where it won't do just what it ooks
like it does.
That it is undefined by the standard is one problem. It means at a
future date the code will stop working.

No, it means that at a future date the code might stop working. That's
not to say that it's a good way to write code, but hyperventilatin g is
not a good way to start a design.
I think there is quite a difference between intending to use formally
undefined behaviour in a new design and changing existing code that
works when you discover it relies on formally undefined behaviour.

Personally, for a new design my initial position would be to avoid any
code for which the behaviour is undefined. With an existing code base,
if I was satisfied that the behaviour on my particular compiler and
platform was as intended, my initial position would be if it ain't
broken, don't fix it. Of course, formally the code is broken by
definition. But in practice I would take into account whether I
expected to be changing compilers any time soon, and how much
regression test coverage I had of the code before deciding whether to
change it.

Gavin Deane

Dec 10 '06 #7

Glen Dayton wrote:
While looking at some old code I ran across a snippet that
increments a pointer to access different members of a structure:
...

struct Badness {
std::string m_begin;
std::string m_param1;
std::string m_param2;
std::string m_end;

Badness();
};
...
Badness badness;

std::string *it = &badness.m_begi n;

for (++it; it != &badness.m_e nd; ++it) {
std::cout << it->c_str() << std::endl;
}

It just looks wrong. It depends on all of the members of class
or structure to be consistent so its bad from a maintenance
standpoint. It seems evil to use a pointer beyond the specific
object for which it is defined.

Looking wrong and evil, though, are not rational arguments that
would allow me to convince my technical lead that this code
needs to be changed sooner than later.

Anyone have good talking points?

/Glen
Loose the pointers.
Can you not do something like this? Note: you must keep the
std::vector< std::string container at the top of the struct in order
to guarentee that it is initialized before the references.

#include <iostream>
#include <ostream>
#include <string>
#include <vector>
#include <iterator>

struct Badness {
private:
std::vector< std::string vs;
public:
std::string& m_begin;
std::string& m_param1;
std::string& m_param2;
std::string& m_end;
typedef std::vector< std::string >::iterator baditerator;
typedef std::vector< std::string >::const_iterat or const_baditerat or;

Badness() : vs(4),
m_begin(vs[0]), m_param1(vs[1]),
m_param2(vs[2]), m_end(vs[3])
{ }
baditerator begin() { return vs.begin(); }
baditerator end() { return vs.end(); }

// friend
friend std::ostream&
operator<<(std: :ostream& os, const Badness& r_bad)
{
std::copy( r_bad.vs.begin( ),
r_bad.vs.end(),
std::ostream_it erator< std::string >(os, "\n") );
return os;
}
};

int main()
{
Badness badness;
badness.m_begin = "string m_begin";
badness.m_param 1 = "string m_param1";
badness.m_param 2 = "string m_param2";
badness.m_end = "string m_end";

for (Badness::badit erator iter = badness.begin() ;
iter != badness.end();
++iter)
{
std::cout << *iter << std::endl;
}

std::cout << "\n using op<<...\n";
std::cout << badness;
}

Dec 10 '06 #8
Gavin Deane wrote:
Of course, formally the code is broken by
definition.
For a somewhat artificial definition of "broken." If it does what it's
supposed to do most people wouldn't consider it broken.
But in practice I would take into account whether I
expected to be changing compilers any time soon, and how much
regression test coverage I had of the code before deciding whether to
change it.
Portability is not an absolute. It's about how hard it is to move to a
different platform. Code that's well formed according to the language
definition isn't automatically easier to port than code that isn't.
Compilers vary.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
Dec 10 '06 #9

Pete Becker wrote:
Gavin Deane wrote:
Of course, formally the code is broken by
definition.

For a somewhat artificial definition of "broken." If it does what it's
supposed to do most people wouldn't consider it broken.
It does what it's supposed to do, but how do I know that? Where is the
specification that defines what behavior that code should have?

If I am relying on undefined behaviour, the simple fact that there is
nowhere I can go to read documentation that explains what the behaviour
should be makes me uncomfortable as an engineer. Operating outside the
world of specification is moving away from sound engineering principles
and towards voodoo. I would suggest that a software engineer should
only do that with good reason.

Gavin Deane

Dec 10 '06 #10

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

Similar topics

1
1268
by: Christian Nolte | last post by:
I want to implement dynamic calling of interface methods using pointers to members and have some trouble to get it right. An example of what I am talking about looks like that: /////////////////////////////////////////////// class StdInterface { public: int func(void) {return 1;} int func2(void) {return 2;} };
4
1771
by: Oystein Haare | last post by:
Is it best to declare class member objects as pointers or not pointers? class A { public: A(int i); //.... };
4
4739
by: Steven T. Hatton | last post by:
I mistakenly set this to the comp.std.c++ a few days back. I don't believe it passed the moderator's veto - and I did not expect or desire anything different. But the question remains: ISO/IEC 14882:2003(E) §8.5 says:   To zero-initialize an object of type T means: 5   -- if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
5
2182
by: pmatos | last post by:
Hi all, I have a style question. I've been for long programming in Lisp-like languages and C when I need a low-level language. Now, I'm programming for professional reasons in C++ (which I had programmed in before but only in college) and I'm getting to like it, however I'm having some issues with style. For example, If I have an object which I define as a private member of a class, for
6
2471
by: lovecreatesbeauty | last post by:
Hello Experts, Why static data members can be declared as the type of class which it belongs to? Inside a class, non-static data members such as pointers and references can be declared as type of its own class. Non-static data members can not be declared as type of its own class (excluding pointers and references).
4
1244
by: Paolo Capriotti | last post by:
Compiling the following code (gcc 3.3.6), I get an invalid conversion error. Is there a valid reason why this conversion can't be performed? --- class A {}; class B : public A {}; class T {
3
5796
by: Ryan Steckler | last post by:
I found this behavior while trying to implement a singleton class. Below is a somewhat more straight forward example, though admittedly less useful in real life. The basic problem is that when a static property of a class is called (StaticInit.MyProperty), the property code executes BEFORE the static members are initialized. This would lead one to assume that the static members would equate to null, but that isn't the case either. They...
14
2641
by: lovecreatesbea... | last post by:
Could you tell me how many class members the C++ language synthesizes for a class type? Which members in a class aren't derived from parent classes? I have read the book The C++ Programming Language, but there isn't a detail and complete description on all the class members, aren't they important to class composing? Could you explain the special class behavior in detail? Thank you very much.
6
8160
by: Bhawna | last post by:
I am into c++ code maintenance for last 3-4 years but recently I am put into design phase of a new project. Being a small comapany I dont have enough guidance from seniors. Currently I am into a situation where I am implementing base class functions by including a pointer to subclass member in base class. Reason being functionality is common for subclasses but the members are common within subclass only (static member of subclass) but...
0
9462
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
10046
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9886
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9857
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
9722
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...
0
5155
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
5318
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3817
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3369
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.