Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Idiots (reprise)

94 views
Skip to first unread message

Mr Flibble

unread,
Aug 26, 2016, 5:23:09 PM8/26/16
to
Some of the idiotic things that regulars of this newsgroup still,
presumably, continue to advocate:

1) Don't use the unsigned integral types despite the fact that the C++
standard library is full of their use.
2) Don't use abstract interfaces (as they advocate against using public
virtual functions).
3) Never derive from standard containers despite the fact that interface
augmentation is useful.
4) Don't use reference members despite the fact that not all classes
need to be Assignable.
5) Use the memory allocated by std::vector<POD>::reserve() without
constructing elements by bypassing std::vector's modification functions
(e.g. push_back).

Use this newsgroup with caution.

/Flibble

Ian Collins

unread,
Aug 26, 2016, 5:27:45 PM8/26/16
to
Examples? I don't recall anyone here advocating any of the above.

--
Ian

Mr Flibble

unread,
Aug 26, 2016, 5:35:29 PM8/26/16
to
Ask Alf.

/Flibble


Wouter van Ooijen

unread,
Aug 26, 2016, 5:50:53 PM8/26/16
to
> 2) Don't use abstract interfaces (as they advocate against using public
> virtual functions).

This one I don't understand. What is the problem with avoiding public
virtual functions?

Wouter "objects? No thanks!" van Ooijen


Jerry Stuckle

unread,
Aug 26, 2016, 7:19:31 PM8/26/16
to
Only a crap programmer would make statements like this.

You're right - use this newsgroup with caution. There are way too many
crap programmers promoting crap programming practices.

--
==================
Remove the "x" from my email address
Jerry Stuckle
jstu...@attglobal.net
==================

Daniel

unread,
Aug 26, 2016, 7:26:23 PM8/26/16
to
On Friday, August 26, 2016 at 5:23:09 PM UTC-4, Mr Flibble wrote:
> Some of the idiotic things that regulars of this newsgroup still,
> presumably, continue to advocate:
>
> 3) Never derive from standard containers despite the fact that interface
> augmentation is useful.

For what reason would you want to derive from standard containers? Interface
augmentation? Use free functions.

> 4) Don't use reference members despite the fact that not all classes
> need to be Assignable.

You don't need to hold reference variables and lose assignability, you can always do, e.g.

class buffered_ostream
{
std::ostream* os_ptr_;
public:
buffered_ostream(std::ostream& os)
: os_ptr_(std::addressof(os))

Daniel

Ian Collins

unread,
Aug 26, 2016, 9:53:22 PM8/26/16
to
On 08/27/16 11:26 AM, Daniel wrote:
> On Friday, August 26, 2016 at 5:23:09 PM UTC-4, Mr Flibble wrote:
>> Some of the idiotic things that regulars of this newsgroup still,
>> presumably, continue to advocate:
>>
>> 3) Never derive from standard containers despite the fact that interface
>> augmentation is useful.
>
> For what reason would you want to derive from standard containers? Interface
> augmentation? Use free functions.

More likely interface restriction although containment rather than
inheritance is often a better choice.

The key point to remember with standard containers is they aren't
designed to be base classes (missing a virtual destructor). If you do
derive from a standard container the safest option is private inheritance.

--
Ian

Gareth Owen

unread,
Aug 27, 2016, 12:50:00 AM8/27/16
to
Daniel <daniel...@gmail.com> writes:

> On Friday, August 26, 2016 at 5:23:09 PM UTC-4, Mr Flibble wrote:
>> Some of the idiotic things that regulars of this newsgroup still,
>> presumably, continue to advocate:
>>
>> 3) Never derive from standard containers despite the fact that interface
>> augmentation is useful.
>
> For what reason would you want to derive from standard containers? Interface
> augmentation? Use free functions.

I've done it for things like (simplified):

class CartesianCoord3 : public std::vector<double,3>
{
public:
double& x(void) { return operator[](0);}
double& y(void) { return operator[](1);}
double& z(void) { return operator[](2);}
};

It means you get all the iterator types for free without having to
declare / define them. The key is never let ownership of the object
belong to a pointer to the base class (so the virtual destructor is not
an issue).

Another thing that I've found helpful is using trivial inheritance for
type safety:

/// [0], [1], [2] are (x,y,z)
class CartesianCoord3 : public std::vector<double,3>{
};

/// [0], [1], [2] are (r,phi,psi)
class PolarCoord3 : public std::vector<double,3>{
};

Although the objects are identical, I can't pass a CartesianCoord3 to a
function that expects a PolarCoord3, or vice versa. Or I can define
explicit conversion operators between the two (Here Be Dragons).

Actual technical question:
if I inherit from base class with a non-virtual destructor, but don't add
any members am I OK destroying the object through a pointer-to-base?

What if I don't add any data members (i.e. interface augmentation only)?

What if I add only POD data members?

Öö Tiib

unread,
Aug 27, 2016, 5:44:38 AM8/27/16
to
That key point feels like red herring for so many reasons. Why we got
owning raw pointer to dynamically allocated object's standard container
base sub-object somewhere? Isn't pointer to standard container overly
dynamic memory management and one indirection too many? IMHO we
idiomatically use standard container objects. Ok, lets imagine that we
have some rather odd reason for example that the ownership of container
is shared. But then isn't it overly manual resource management? IMHO we typically use smart pointers on such case and those store deleter of
most derived object. And finally what was the point of deriving that
class if the owner of object uses pointer to base? Standard containers
do not have virtual functions so IMHO it was pointlessly derived then.


mark

unread,
Aug 27, 2016, 5:45:38 AM8/27/16
to
On 2016-08-27 06:49, Gareth Owen wrote:
> Actual technical question:
> if I inherit from base class with a non-virtual destructor, but don't add
> any members am I OK destroying the object through a pointer-to-base?
>
> What if I don't add any data members (i.e. interface augmentation only)?
>
> What if I add only POD data members?

It's undefined behavior no matter what.

C++11/14 standard 5.3.5
<<<
In the first alternative (delete object), if the static type of the
object to be deleted is different from its dynamic type, the static type
shall be a base class of the dynamic type of the object to be deleted
and the static type shall have a virtual destructor or the behavior is
undefined.
>>>

Richard Damon

unread,
Aug 27, 2016, 1:37:35 PM8/27/16
to
On 8/27/16 12:49 AM, Gareth Owen wrote:
>
> Actual technical question:
> if I inherit from base class with a non-virtual destructor, but don't add
> any members am I OK destroying the object through a pointer-to-base?
>
> What if I don't add any data members (i.e. interface augmentation only)?
>
> What if I add only POD data members?
>

As has been stated, you are in the domain of undefined behavior once you
use a non-virtual destructor that doesn't match the real type of the object.

In practice, if you are willing to use implementation non-defined
behavior (so no complaining if at some point the compiler gets smart
enough that things break), the interface augmentation only case should
normally work, as your destructor, if it was called via the virtual
mechanism, would be totally null. The POD data members only method is
also fairly safe, the one question would be if the compiler, by being
able to make a wrong assumption about the size of the object, might trip
you up with an erroneous small object optimization for deallocation.


Gareth Owen

unread,
Aug 27, 2016, 2:00:41 PM8/27/16
to
mark <ma...@invalid.invalid> writes:

> On 2016-08-27 06:49, Gareth Owen wrote:
>> Actual technical question:
>> if I inherit from base class with a non-virtual destructor, but don't add
>> any members am I OK destroying the object through a pointer-to-base?
>>
>> What if I don't add any data members (i.e. interface augmentation only)?
>>
>> What if I add only POD data members?
>
> It's undefined behavior no matter what.

Yeah, that's what I expected.

Gareth Owen

unread,
Aug 27, 2016, 2:01:14 PM8/27/16
to
Thanks

Mr Flibble

unread,
Aug 27, 2016, 2:04:19 PM8/27/16
to
Gareth Owen <gwo...@gmail.com> wrote:

>
> Another thing that I've found helpful is using trivial inheritance for
> type safety:
>
> /// [0], [1], [2] are (x,y,z)
> class CartesianCoord3 : public std::vector<double,3>{
> };
>
> /// [0], [1], [2] are (r,phi,psi)
> class PolarCoord3 : public std::vector<double,3>{
> };

Isn't C++ getting strong typedefs as a better solution for this?

/Flibble

mark

unread,
Aug 27, 2016, 3:34:36 PM8/27/16
to
On 2016-08-27 19:37, Richard Damon wrote:
>>
>
> As has been stated, you are in the domain of undefined behavior once you
> use a non-virtual destructor that doesn't match the real type of the
> object.
>
> In practice, if you are willing to use implementation non-defined
> behavior (so no complaining if at some point the compiler gets smart
> enough that things break), the interface augmentation only case should
> normally work, as your destructor, if it was called via the virtual
> mechanism, would be totally null. The POD data members only method is
> also fairly safe, the one question would be if the compiler, by being
> able to make a wrong assumption about the size of the object, might trip
> you up with an erroneous small object optimization for deallocation.

Things are potentially much worse than that. E.g:

class A : public std::vector<...> {}

If you try to delete A via a pointer to vector<>, the compiler may
conclude that your pointer cannot point to an A* (since the deletion
would be undefined behavior). It may draw all kinds of funny conclusions
for prior usage of that pointer (e.g. about aliasing that cannot happen)
and result in wrong code generation.

This is not a theoretical concern, unexpected optimizations based on
undefined behavior have happened. E.g. in the Linux Kernel:

static unsigned int tun_chr_poll(struct file *file, poll_table * wait) {
struct tun_file *tfile = file->private_data;
struct tun_struct *tun = __tun_get(tfile);
struct sock *sk = tun->sk;
unsigned int mask = 0;
if (!tun) return POLLERR;
...

"if (!tun) return POLLERR;" was optimized away by GCC, since "*sk =
tun->sk;" is undefined behavior if tun is NULL.

https://lwn.net/Articles/342330/

bitrex

unread,
Aug 27, 2016, 5:30:38 PM8/27/16
to
I'm no expert in the C++, particularly its modern incarnations, but I
thought it was always good practice to make virtual functions
protected/private and wrap them in a public interface in the superclass.

Am I a dumb?

Gareth Owen

unread,
Aug 28, 2016, 1:36:00 AM8/28/16
to
Mr Flibble <flibbleREM...@i42.co.uk> writes:

> Isn't C++ getting strong typedefs as a better solution for this?

Maybe, I've no idea. I don't really follow that. I've only just caught
up with C++11 in the last year or so.

Certainly, strong typedefs would be a preferable solution.

Gareth Owen

unread,
Aug 28, 2016, 1:41:02 AM8/28/16
to
mark <ma...@invalid.invalid> writes:

> If you try to delete A via a pointer to vector<>, the compiler may
> conclude that your pointer cannot point to an A* (since the deletion
> would be undefined behavior). It may draw all kinds of funny
> conclusions for prior usage of that pointer (e.g. about aliasing that
> cannot happen) and result in wrong code generation.

Good observation. [snip Linux kernel example]. I've seen similar
examples on Raymond Chen's MSDN blog, where he shows that UB to do what
he calls "time travel"
https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=633/

Bo Persson

unread,
Aug 28, 2016, 4:28:16 AM8/28/16
to
I think it is about the *always*.

If it is just a wrapper around the call, what's the use of the wrapper?

Sometimes it looks just like having setters for all the private
variables, because making them public is supposed to be bad. Not *always*.


Bo Persson

bitrex

unread,
Aug 28, 2016, 2:05:32 PM8/28/16
to
On 08/28/2016 04:28 AM, Bo Persson wrote:
> On 2016-08-27 23:30, bitrex wrote:
>> On 08/26/2016 05:50 PM, Wouter van Ooijen wrote:
>>>> 2) Don't use abstract interfaces (as they advocate against using public
>>>> virtual functions).
>>>
>>> This one I don't understand. What is the problem with avoiding public
>>> virtual functions?
>>>
>>> Wouter "objects? No thanks!" van Ooijen
>>>
>>>
>>
>> I'm no expert in the C++, particularly its modern incarnations, but I
>> thought it was always good practice to make virtual functions
>> protected/private and wrap them in a public interface in the superclass.
>>
>> Am I a dumb?
>
> I think it is about the *always*.
>
> If it is just a wrapper around the call, what's the use of the wrapper?

I guess the notion is that if you have an abstract class say like:

class AbstractFoo {
public:
virtual ~Foo() = default;

void do_stuff()
{
_do_stuff();
}

private:
virtual void _do_stuff() = 0;

protected:
Foo() = default;
};

And then if at some point later you realize you want all Foos to have a
somewhat different behavior when "do_stuff" is called you can just
change the interface defined by the abstract class to be:

class AbstractFoo {
public:
virtual ~Foo() = default;

void do_stuff()
{
_do_the_first_stuff();
_do_stuff();
}

private:
void _do_the_first_stuff() { blah blah; }
virtual void _do_stuff() = 0;

protected:
Foo() = default;
};

Without having to change the implementation in all the subclasses.

> Sometimes it looks just like having setters for all the private
> variables, because making them public is supposed to be bad. Not *always*.

Again, in my limited experience, I would posit that having a bunch of
getters/setters for all the private variables is indicative of poor
design. I think I would try to only use getters and setters in the case
of POD structs. Otherwise encapsulation is being broken - I think
ideally there shouldn't be any need for other objects to look at the
private variables of a more complex class; that's for their own internal
state.

> Bo Persson
>

Öö Tiib

unread,
Aug 28, 2016, 5:29:05 PM8/28/16
to
Yes, so initially there is a 'do_stuff' wrapper for mere potential
to rethink its implementation in inheritance tree for example to
instrument it with that '_do_the_first_stuff'. It predicts that need
for that wrapper in future is likely and that changing implementation
details later if and when needed is more difficult than right now.

>
> > Sometimes it looks just like having setters for all the private
> > variables, because making them public is supposed to be bad. Not *always*.
>
> Again, in my limited experience, I would posit that having a bunch of
> getters/setters for all the private variables is indicative of poor
> design. I think I would try to only use getters and setters in the case
> of POD structs. Otherwise encapsulation is being broken - I think
> ideally there shouldn't be any need for other objects to look at the
> private variables of a more complex class; that's for their own internal
> state.

You are correct but that is issue of different level.

The getters and setters are considered better than to have public data
members *despite* those break encapsulation as bad as public data members.
The typical explanation is again that those allow that the implementation
details can change and instrumentation (with validators?) can occur in
future etc.

That is controversial on both cases. We add sort of bloat without
real meat and speculate about "easier" future. We may be correct in
specific case but adding "always" to it is bordering on lie. We can't
predict future in generic manner. ;)

Scott Lurndal

unread,
Aug 29, 2016, 8:53:25 AM8/29/16
to
Mr Flibble <flibbleREM...@i42.co.uk> writes:
>Some of the idiotic things that regulars of this newsgroup still,
>presumably, continue to advocate:
>
>1) Don't use the unsigned integral types despite the fact that the C++
>standard library is full of their use.

Actually, if you're working with unsigned data, use unsigned
types. If you're working with signed data, use signed types.

In all cases, use the matching datatype for system interfaces
whether they're in C or C++ headers.

>2) Don't use abstract interfaces (as they advocate against using public
>virtual functions).

Use abstract interfaces (pure virtual classes) as interfaces (a la Java)
where it makes sense so-to-do.

Rick C. Hodgin

unread,
Aug 29, 2016, 9:30:00 AM8/29/16
to
On Friday, August 26, 2016 at 5:23:09 PM UTC-4, Mr Flibble wrote:
> Some of the idiotic things that regulars of this newsgroup still,
> presumably, continue to advocate:
>
> [snip]

Leigh, you could consider using your position of greater knowledge and/or
experience to help teach people who may not know better. Teaching will
invariably accomplish far more than berating.

Best regards,
Rick C. Hodgin
0 new messages