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 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
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)
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
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;
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)
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
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;
}
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)
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 This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
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;}
};
|
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);
//....
};
|
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;
|
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
|
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).
| |
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 {
|
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...
|
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.
|
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...
|
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...
|
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...
| |
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...
|
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,...
|
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...
|
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...
|
by: adsilva |
last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
|
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
| |
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
| |