Tuesday, April 21, 2015

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

Christopher Pisz <nospam@notanaddress.com>: Apr 20 05:54PM -0500

On 4/20/2015 5:24 PM, Stefan Ram wrote:
SNIP
 
> ::std::vector< ::std::unique_ptr< Fish >> w;
> for( auto & f: v )w.push_back( f->clone() ); /* copying is here */
> for( auto & f: w )f->print(); }
 
Still catching up on the C++11 standard.
 
What do the override and final keywords actually accomplish? Is its only
purpose to provide compiler errors if the base didn't have a matching
virtual method signature? Or does it do something else, perhaps some
kind of optimization?
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
Luca Risolia <luca.risolia@linux-projects.org>: Apr 21 01:06AM +0200

Il 20/04/2015 23:28, Paavo Helde ha scritto:
> vector<std::shared_ptr<Fish>> vecOfFish;
> vecOfFish.push_back(std::shared_ptr<Fish>(new Tuna()));
> vecOfFish.push_back(std::shared_ptr<Fish>(new Carp()));
 
Use std::make_shared() whenever possible. It's more efficient and more
compact (in terms of both object and source code).
 
In this case:
vecOfFish.push_back(std::make_shared<Tuna>());
vecOfFish.push_back(std::make_shared<Carp>());
Melzzzzz <mel@zzzzz.com>: Apr 21 04:23AM +0200

On 21 Apr 2015 01:36:10 GMT
 
> I wanted to make »print« public, but forgot to
> make it public in »class Tuna«.
 
> Is this good or bad style?
 
Well, one can't call print on Tuna but can on Fish.
I remember it was considered to be good style to make virtual functions
private and call them from base class non virtual functions eg:
 
class Base {
public:
void f() {
virt();
}
}
private:
virtual void virt()=0;
};
 
class Derived : public Base {
void virt() {}
};
 
Derived d; d.f();
Victor Bazarov <v.bazarov@comcast.invalid>: Apr 21 12:03AM -0400

On 4/20/2015 7:06 PM, Luca Risolia wrote:
 
> In this case:
> vecOfFish.push_back(std::make_shared<Tuna>());
> vecOfFish.push_back(std::make_shared<Carp>());
 
Given 'class Derived : public Base {};', is 'shared_ptr<Derived>'
convertible to 'shared_ptr<Base>'? Your suggestion seems to imply as
much...
 
V
--
I do not respond to top-posted replies, please don't ask
Ian Collins <ian-news@hotmail.com>: Apr 21 04:46PM +1200

Christopher Pisz wrote:
> purpose to provide compiler errors if the base didn't have a matching
> virtual method signature? Or does it do something else, perhaps some
> kind of optimization?
 
Mainly the former.
 
It also provides a better form of documentation than prefixing virtual
function overrides with "virtual" as required by some older coding
standards I've sen.
 
--
Ian Collins
Paavo Helde <myfirstname@osa.pri.ee>: Apr 21 12:00AM -0500

Christopher Pisz <nospam@notanaddress.com> wrote in news:mh400q$r4o$1@dont-
email.me:
 
> purpose to provide compiler errors if the base didn't have a matching
> virtual method signature? Or does it do something else, perhaps some
> kind of optimization?
 
The final keyword can be used for optimization as the compiler can
potentially replace some virtual calls by non-virtual and maybe even inline
them. However, I guess this is not the main reason because if this is
possible it means that making the function virtual was not really necessary
in the first place (at least not in this usage scenario).
 
The override keyword is just for producing compiler errors, but it is
immensely useful when refactoring a large code base. I guess final could
also be useful in some kind of (more radical) refactoring.
 
Cheers
Paavo
Paavo Helde <myfirstname@osa.pri.ee>: Apr 21 12:30AM -0500

ram@zedat.fu-berlin.de (Stefan Ram) wrote in news:private-20150421033347
 
> I wanted to make »print« public, but forgot to
> make it public in »class Tuna«.
 
> Is this good or bad style?
 
Yes, you can have private virtual functions in C++. The access checks are
done at compile time only and are based on the static type of the
pointer/reference through which the virtual function is called. At run-
time the program does not know or care any more if some vtable slot
points to a private or non-private virtual function override.
 
This is most useful if the access is uniformly private in all classes of
the hierarchy. In your example (public in the base, private in derived)
it is just a bit confusing and does not accomplish much. But according to
the ideology of C++, a half-accidental language feature like this is not
locked down just because there is no clear usage case or it could be
potentially misused. Instead, the programmer is trusted to use or not use
the features as he sees fit.
 
Cheers
Paavo
legalize+jeeves@mail.xmission.com (Richard): Apr 21 03:29PM

[Please do not mail me a copy of your followup]
 
Luca Risolia <luca.risolia@linux-projects.org> spake the secret code
 
>In this case:
> vecOfFish.push_back(std::make_shared<Tuna>());
> vecOfFish.push_back(std::make_shared<Carp>());
 
Even better: if you just need a container of polymorphic objects use
std::unique_ptr<T> and std::make_unique[*].
 
I see people over-usign shared_ptr when unique_ptr would suffice.
 
[*] if your implementation doesn't yet have make_unique or unique_ptr,
then consider using an alternative from boost.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Luca Risolia <luca.risolia@linux-projects.org>: Apr 21 06:16PM +0200

On 21/04/2015 17:29, Richard wrote:
>> vecOfFish.push_back(std::make_shared<Carp>());
 
> Even better: if you just need a container of polymorphic objects use
> std::unique_ptr<T> and std::make_unique[*].
 
If it's better clearly depends on the real application. unique_ptr's are
inadequate, if you need to copy the vector for some reasons.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Apr 21 05:33PM +0100

On 21/04/2015 16:29, Richard wrote:
[snip]
 
> I see people over-usign shared_ptr when unique_ptr would suffice.
 
> [*] if your implementation doesn't yet have make_unique or unique_ptr,
> then consider using an alternative from boost.
 
There is no alternative to unique_ptr in Boost as unique_ptr requires
move semantics and Boost won't magically give you move semantics sausages.
 
/Flibble
Luca Risolia <luca.risolia@linux-projects.org>: Apr 21 08:22PM +0200

Il 21/04/2015 06:03, Victor Bazarov ha scritto:
 
> Given 'class Derived : public Base {};', is 'shared_ptr<Derived>'
> convertible to 'shared_ptr<Base>'?
 
Yes, although they are not covariant.
ram@zedat.fu-berlin.de (Stefan Ram): Apr 21 01:36AM

> virtual ::std::unique_ptr< Fish >clone() = 0; };
>class Tuna : public Fish
>{ void print () override { puts( "Tuna" ); }
...
>for( auto & f: w )f->print(); }
 
I only now become aware of the fact that the
»print« method of »Tuna« is called by the client,
even though it is »privat« in »class Tuna«!
Or does it »inherit« the »public«?
 
I wanted to make »print« public, but forgot to
make it public in »class Tuna«.
 
Is this good or bad style?
ram@zedat.fu-berlin.de (Stefan Ram): Apr 21 03:13AM

>>So, as the array is temporary, a pointer to its element can and will
>>become dangling as far as I can see.
>I thought the clarification (making the return value a constexpr) takes
 
»constexpr« did not occur so far. A const& can extend the
lifetime of a temporary, but it must be bound to it directly,
not via a pointer.
 
»::std::begin« does not accept an initialization list, only
an array reference, so a temporary array will be created and
the begin pointer of that array will be computed. The result
is a pointer to the begin of that array. Then, that array will
be destroyed. It is as if
 
#include <initializer_list>
#include <iostream>
#include <ostream>
 
struct array
{ array( ::std::initializer_list< int >const ){};
~array(){ ::std::cout << "I, temporary array, destroyed\n"; } };
 
int * begin( array ){ return nullptr; }
 
int main()
{ ::std::cout << "before\n";
const int * y = begin( { 1, 2, 3 }); /* this is like your code */
::std::cout << "after\n";
::std::cout << "y = " << y << '\n'; }
 
before
I, temporary array, destroyed
after
y = 0
 
> Certainly the generated code I've checked for a couple of
>compilers shows the values being accessed from static data.
 
When arguing about C++, the language, C++s, the implementations,
are not authoritative. Or, as Bartosz Milewski puts it:
»The fact that the program works has no relevance.«
ram@zedat.fu-berlin.de (Stefan Ram): Apr 21 05:12AM

>Stefan Ram wrote:
>18.9.3 Initializer list range access
>template<class E> const E* begin(initializer_list<E> il) noexcept;
 
I was not aware of this! Today it is specified as:
 
template<class E> constexpr const E* begin(initializer_list<E> il) noexcept;
Returns: il.begin().
 
. This copies the argument initializer list to the parameter il,
but if the underlying array has static storage duration,
then the pointer will /not/ dangle, indeed.
ram@zedat.fu-berlin.de (Stefan Ram): Apr 21 04:35PM

>. This copies the argument initializer list to the parameter il,
>but if the underlying array has static storage duration,
>then the pointer will /not/ dangle, indeed.
 
I think it's crucial whether the »underlying array« of an initializer list
is a part of the initializer list or is referenced by the initializer list.
 
When it is /referenced/ by the initializer list, the parameter will refer
the same underlying array as the argument, and when this array has static
storage duration, a pointer into it will not dangle.
ram@zedat.fu-berlin.de (Stefan Ram): Apr 21 04:43PM

>If it's better clearly depends on the real application. unique_ptr's are
>inadequate, if you need to copy the vector for some reasons.
 
I just posted code in
 
<deep-copy-20150421001620@ram.dialup.fu-berlin.de>
 
that uses make_unique /and/ copies the vector.
 
Also, it is written in
 
herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/
 
»When in doubt, prefer unique_ptr by default, and you can
always later move-convert to shared_ptr if you need it.«
Ian Collins <ian-news@hotmail.com>: Apr 21 04:36PM +1200

Stefan Ram wrote:
> the begin pointer of that array will be computed. The result
> is a pointer to the begin of that array. Then, that array will
> be destroyed. It is as if
 
18.9.3 Initializer list range access
 
template<class E> const E* begin(initializer_list<E> il) noexcept;
 
1 Returns: il.begin().
 
> { array( ::std::initializer_list< int >const ){};
> ~array(){ ::std::cout << "I, temporary array, destroyed\n"; } };
 
> int * begin( array ){ return nullptr; }
 
So this always returns nullptr.
 
> int main()
> { ::std::cout << "before\n";
> const int * y = begin( { 1, 2, 3 }); /* this is like your code */
 
So this is equivalent to y = nullptr;
 
> I, temporary array, destroyed
> after
> y = 0
 
int main()
{
std::cout << "before\n";
const int * y = std::begin( { 1, 2, 3 }); /* this is like your code */
std::cout << "after\n";
std::cout << "y = " << y << '\n';
}
 
before
after
y = 0x8051294
 
--
Ian Collins
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: