Sunday, April 12, 2015

Digest for comp.lang.c++@googlegroups.com - 17 updates in 3 topics

David Harmon <source@netcom.com>: Apr 11 10:28PM -0700

On Sat, 11 Apr 2015 18:05:41 +0000 (UTC) in comp.lang.c++, Juha Nieminen
<nospam@thanks.invalid> wrote,
>Btw, define "template metaprogramming".
 
Writing your own c++ templates, as distinguished from using templates
someone else has written or from the standard library.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 12 06:16AM

On Sat, 2015-04-11, Paavo Helde wrote:
 
>> template <class InputIterator>
>> vector(InputIterator, InputIterator)
 
>> the former is a decent match, and the latter is worse
 
It's not worse, of course -- it's a perfect match, with
InputIterator = int. Sorry for confusing things.
 
>> (and wouldn't compile anyway if it was chosen).
 
> 10 and 20 are of type int, which is different from size_type and const
> size_t&. A little experiment shows this is not so trivial:
 
[snip]
 
> second constructor to fail at the substitution stage (SFINAE) for integer
> types so that the first constructor gets selected. And yes, switching
> overloads on and off at compile time seems pretty TMP for me.
 
Whatever it is, I now see it's worth understanding.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Paavo Helde <myfirstname@osa.pri.ee>: Apr 12 02:57AM -0500

David Harmon <source@netcom.com> wrote in news:D8idnXi_a7LFn7fInZ2dnUU7-
>>Btw, define "template metaprogramming".
 
> Writing your own c++ templates, as distinguished from using templates
> someone else has written or from the standard library.
 
This might be a useful definition, but not exactly what the OP was
interested in. He asked: "Is template metaprogramming a serious
programming technique, used in real-life code?" and "Is template
metaprogramming allowed by the standard?"
 
These are actually a bit orthogonal questions, but answer to both is yes.
The standard library and many other template libraries (including many
Boost libraries, for example) are pretty serious and used very heavily in
real world. And yes, this is all backed up by the standard.
 
As always, any given C++ compilers might lack or misbehave with some
(typically newer or more exotic) template features, but this is no
different from non-template features.
 
Cheers
Paavo
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 12 09:00AM

On Sun, 2015-04-12, David Harmon wrote:
>>Btw, define "template metaprogramming".
 
> Writing your own c++ templates, as distinguished from using templates
> someone else has written or from the standard library.
 
That's not how most people use the term. Stroustrup has a rather long
discussion about the difference between generic programming and
template metaprogramming: The C++ Programming Language, 4th ed,
section 28.1. Sorry, I'm too lazy to quote or summarize it.
 
/Exactly/ where the border between the two goes is, for me personally,
not that interesting.
 
I hope there isn't a trend to spread fear and doubt about generic
programming, by associating it with template metaprogramming. The
former is obviously useful to almost everyone, and nothing to be
afraid of. The latter is ... well, I haven't quite grasped it in
practice yet.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Apr 12 05:08PM +0100

On Fri, 10 Apr 2015 15:22:18 -0700 (PDT)
> metaprogramming merely a curiosity, an unexpected side effect of
> adding templates to language definition and everything about it is
> either undefined or implementation defined?
 
Compile time programming using templates is entirely standardized, in
the sense that templates are standardized. It is sometimes said that
TMP is an unexpected side effect of creating a template system
originally intended for "cookie cutting", but it is now well used both
within the standard library and by other libraries. std::tuple for
example is implemented using TMP with recursive inheritance. C++11/14
also provides a complete type trait library providing (amongst other
things) compile time predicates and type transformations.
 
One implied question that you have asked is the extent to which
compilers correctly implement templates in conformity with the
standard. In my experience, gcc >= 4.8, and clang >= 3.4, are nearly
completely conformant with respect to templates. Earlier versions of
gcc correctly implement type traits (I believe from around gcc-4.3 or
4.4 onwards - it is a long time since I used those compilers) but have
a number of infelicities at the edges. Recent versions of visual
studio are reputed to be more or less completely compliant.
 
If you are writing an average program, you may never need to know about
or understand TMP. The libraries used by the program will do the work
for you. If you are writing a library for C++11 or C++14 you will
probably at least use the type traits library and quite probably a great
deal more. To take a simple example, if you are forwarding arguments
using C++11/14 "universal"/"collapsible" references, you may well find
yourself needing to use std::remove_reference to convert a deduced
reference type where an lvalue is passed to the underlying type when
instantiating a template. This is trivial to do but would generally be
classed as compile time meta programming.
 
Chris
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 12 11:26PM

On Sun, 2015-04-12, Chris Vine wrote:
...
> TMP is an unexpected side effect of creating a template system
> originally intended for "cookie cutting", but it is now well used both
> within the standard library and by other libraries.
 
And Stroustrup's angle on that is at
 
http://www.stroustrup.com/bs_faq.html#understand
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
"Norman J. Goldstein" <normvcr@telus.net>: Apr 12 12:57AM -0700

I would find it helpful for a shared_ptr to have an id() method, so that
two shared_ptr's manage the same object only if and only if they have
the same id's. If the managed object is not NULL, then the address of
the object can work as an id. Obviously, this does not work if the
object is NULL. An easy way to implement id(), for example, would be to
return the address of the location that stores the link count for the
shared_ptr.
 
Any thoughts on this?
Marcel Mueller <news.5.maazl@spamgourmet.org>: Apr 12 10:19AM +0200

On 12.04.15 09.57, Norman J. Goldstein wrote:
> the same id's. If the managed object is not NULL, then the address of
> the object can work as an id. Obviously, this does not work if the
> object is NULL.
 
Why not?
 
If a pointer does not point to an object then there is no definition of
"the same object".
 
And it is common practice and sometimes very useful that
reference-equals comparisons return true if both operands point to the
same object /or/ both are NULL.
 
> return the address of the location that stores the link count for the
> shared_ptr.
 
> Any thoughts on this?
 
Not recommended from my point of view.
 
#1 It is already possible to write x.get() == y.get() and the intention
of this comparison is obvious.
 
#2 Wrapping this by an id() function would allow to compare pointers of
incompatible type without an error.
 
#3 The data type of the id() cannot be safely int when sizeof(int) is
less than sizeof(X*).
 
 
Marcel
Paavo Helde <myfirstname@osa.pri.ee>: Apr 12 06:57AM -0500

"Norman J. Goldstein" <normvcr@telus.net> wrote in news:mgd8gt$pil$1
> object is NULL. An easy way to implement id(), for example, would be to
> return the address of the location that stores the link count for the
> shared_ptr.
 
This would not work if the link count is embedded in the linked object or
added to it via std::make_shared().
 
Also, conceptually I do not get why such a feature would be useful. A
smartpointer becomes NULL only if I assign NULL to it. Why should it then
remember to which object it pointed earlier? If I wanted to remember that,
I would not have assigned NULL to it in the first place.
 
Cheers
Paavo
"Öö Tiib" <ootiib@hot.ee>: Apr 12 06:02AM -0700

On Sunday, 12 April 2015 11:20:06 UTC+3, Marcel Mueller wrote:
 
> And it is common practice and sometimes very useful that
> reference-equals comparisons return true if both operands point to the
> same object /or/ both are NULL.
 
Yes, that is common practice.
 
> of this comparison is obvious.
 
> #2 Wrapping this by an id() function would allow to compare pointers of
> incompatible type without an error.
 
It may be desirable to compare smart pointers of incompatible type
to find out if they do (or do not) alias to same most derived object.
The expression above does not compile on case where 'x' is
'std::shared_ptr<base_1>' and 'y' is 'std::shared_ptr<base_2>'
and 'base_1' and 'base_2' are unrelated base classes. The
'x' and 'y' may actually use same reference counter if there is
multiple inheritance. To resolve the issue we can write:
 
dynamic_cast<void*>(x.get()) == dynamic_cast<void*>(y.get())
 
However that looks ugly (can be mitigated with inline function)
requires RTTI and is likely less efficient than to compare addresses
of reference counter if any. Both efficiency difference and the
ugliness grow when at least one is 'weak_ptr'.
 
> #3 The data type of the id() cannot be safely int when sizeof(int) is
> less than sizeof(X*).
 
Why it must be 'int'? To me it seems that OP clearly wrote that his
simplest implementation returns address of reference count. Reference
count is 'long' by C++ standard, Address to it is 'long*'. So 'id()'
can return 'void const*' or 'intptr_t'.
"Öö Tiib" <ootiib@hot.ee>: Apr 12 06:29AM -0700

On Sunday, 12 April 2015 14:57:31 UTC+3, Paavo Helde wrote:
> > shared_ptr.
 
> This would not work if the link count is embedded in the linked object or
> added to it via std::make_shared().
 
Why it won't work? The reference count of 'shared_ptr' (and 'weak_ptr')
must be 'long int' regardless of where it is stored. Its address can't
move around in memory during life-time of referenced object.
 
> smartpointer becomes NULL only if I assign NULL to it. Why should it then
> remember to which object it pointed earlier? If I wanted to remember that,
> I would not have assigned NULL to it in the first place.
 
Maybe what he wants is something achievable with
'std::shared_ptr::owner_before' or 'std::shared_ptr::owner_less'. He did
not describe it too well.
"Norman J. Goldstein" <normvcr@telus.net>: Apr 12 10:03AM -0700

Thanks for all the responses. I will address all the comments and
clarify, further.
 
On Sunday, 12 April 2015 11:20:06 UTC+3, Marcel Mueller wrote:
 
> And it is common practice and sometimes very useful that
> reference-equals comparisons return true if both operands point to the
> same object /or/ both are NULL.
*> Yes, that is common practice.
 
In the case of shared_ptr's, it is wrong, in my situation, to take a
NULL pointer as a shared reference. I am interested only in the
relationship reflected by the use_count() .
 
A NULL pointer has an address, say, of 0, so this cannot be used to
determine whether two shared_ptr's are managing the same object. If one
of the two shared_ptr's does reset( new T ), then the two shared_ptr's
will both be managing a bona fide same object. So, even if the managed
object is NULL, the relationship between the two shared_ptr's is
maintained. The use_count() is (at least) two for the two shared_ptr's,
even if they are sharing only NULL.
 
On 04/12/2015 06:29 AM, Öö Tiib wrote:
>> smartpointer becomes NULL only if I assign NULL to it. Why should it then
>> remember to which object it pointed earlier? If I wanted to remember that,
>> I would not have assigned NULL to it in the first place.
 
As pointed out, above, shared_ptr's do remember the relationship, even
if they are assigned NULL. The point I am making is that I would like
to be able to query that relationship, even if the pointer value is NULL.
 
> Maybe what he wants is something achievable with
> 'std::shared_ptr::owner_before' or 'std::shared_ptr::owner_less'. He did
> not describe it too well.
 
I'm sorry, I don't understand these suggestions. The reason that I want
the id() feature, is so that I can save shared_ptr's to disk, and when
they get restored to RAM, they maintain the same relationship.
Currently, when the shared_ptr's are NULL, I cannot do this. During the
running of the program, one of the shared_ptr's might do a reset( new T
), and all the (intended) shared_ptr's must see the change.
"Öö Tiib" <ootiib@hot.ee>: Apr 12 12:18PM -0700

On Sunday, 12 April 2015 20:03:44 UTC+3, Norman J. Goldstein wrote:
 
> In the case of shared_ptr's, it is wrong, in my situation, to take a
> NULL pointer as a shared reference. I am interested only in the
> relationship reflected by the use_count().
 
The 'use_count()' is required to return zero when 'shared_ptr' is empty.
So if you are not interested in the situation (for example since there
is nothing further to serialize) then why you care if they compare equal
or no?
 
> object is NULL, the relationship between the two shared_ptr's is
> maintained. The use_count() is (at least) two for the two shared_ptr's,
> even if they are sharing only NULL.
 
Every 'shared_ptr<X>' is separate and if one starts to point at
something else then others don't.
 
> On 04/12/2015 06:29 AM, Öö Tiib wrote:
 
Following was written by Paavo Helde:
 
 
> As pointed out, above, shared_ptr's do remember the relationship, even
> if they are assigned NULL. The point I am making is that I would like
> to be able to query that relationship, even if the pointer value is NULL.
 
They aren't required to remember any relationships; empty 'shared_ptr'
is empty regardless if the object at what it pointed still exists
or not. I am not sure what relationship.
 
That was written by me:
 
> I'm sorry, I don't understand these suggestions. The reason that I want
> the id() feature, is so that I can save shared_ptr's to disk, and when
> they get restored to RAM, they maintain the same relationship.
 
http://isocpp.org/wiki/faq/serialization
 
The 'shared_ptr' is like ordinary pointer that can point at object at
what other pointers can point too. It does not provide indexing
services. So you have to maintain some map (for example like
'std::map<std::weak_ptr<X>,unsigned>' or 'std::map<X const*,unsigned>')
to map the shared object you serialize to some numeric id.

> Currently, when the shared_ptr's are NULL, I cannot do this. During the
> running of the program, one of the shared_ptr's might do a reset( new T
> ), and all the (intended) shared_ptr's must see the change.
 
I do not understand. Lets imagine there are two 'shared_ptr's p1 and p2
and two objects o1 and o2. All the 9 combinations of states of
pointers is on following diagram:
 
p1 | p2
--------------
1) null | null
2) null | o1
3) null | o2
4) o1 | null
5) o1 | o1
6) o1 | o2
7) o2 | null
8) o2 | o1
9) o2 | o2
 
What is the difference for p2 if the state transits from 1) to
4) or if the state transits from 5) to 8)? It can't see anything
anyway ... it still is empty or points at o1 and it does not know
where p1 points. Please clarify where is difference and why they
should not compare equal in state 1).
"Norman J. Goldstein" <normvcr@telus.net>: Apr 12 01:09PM -0700

NULL and empty are not the same thing for shared_ptr.
///////////////////////////////
#include <iostream>
#include <memory>
using namespace std;
 
int main( int argc, char* argv[] )
{
shared_ptr< int > s1;
shared_ptr< int > s2( s1 );
 
cout << "s1 links= " << s1.use_count() << endl;
cout << "s2 links= " << s2.use_count() << endl;
 
s1.reset( (int*)nullptr );
s2 = s1;
 
cout << "s1 links= " << s1.use_count() << endl;
cout << "s2 links= " << s2.use_count() << endl;
 
return 0;
}// main
////////////////////////////////
Here is the output of the program:
 
s1 links= 0
s2 links= 0
s1 links= 2
s2 links= 2
 
 
On 04/12/2015 12:18 PM, Öö Tiib wrote:
"Norman J. Goldstein" <normvcr@telus.net>: Apr 12 01:29PM -0700

I think I understand, now, what you are saying.
If the shared_ptr's are managing a NULL, there is no way to get the same
set to manage an actual object.
 
Each shared_ptr contains a pointer to the object. I had imagined that
the pointer to the object was actually in the control block.
 
Thank you.
"Öö Tiib" <ootiib@hot.ee>: Apr 12 02:09PM -0700

On Sunday, 12 April 2015 23:29:29 UTC+3, Norman J. Goldstein wrote:
 
> Each shared_ptr contains a pointer to the object. I had imagined that
> the pointer to the object was actually in the control block.
 
> Thank you.
 
It is bit trickier than that. The shared_ptr has 13 constructors 9 of
what are templates so it can be made to do huge pile of tricks.
There are two object pointers. What shared pointer "owns" (IOW to what
will be called deleter when the use count drops to zero) is pointed
by control block. What shared_ptr "points at" is in shared_ptr itself.
"Öö Tiib" <ootiib@hot.ee>: Apr 12 05:08AM -0700

On Friday, 10 April 2015 18:12:08 UTC+3, Scott Lurndal wrote:
> >either.
 
> Although it works in all of the BCD, EBCDIC, UTF-8 (ASCII subset) and
> USASCII codesets.
 
It is also required by standard to work both in C ([5.2.1]/2) and in
C++ ([lex.charset]/3).
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: