comp.lang.c++
http://groups.google.com/group/comp.lang.c++?hl=en
comp.lang.c++@googlegroups.com
Today's topics:
* A simpler Pimpl Idiom ? - 4 messages, 3 authors
http://groups.google.com/group/comp.lang.c++/t/8c62d669bf4e1562?hl=en
* Question regarding copy constructor - 3 messages, 3 authors
http://groups.google.com/group/comp.lang.c++/t/9e723534f9e94458?hl=en
* scoped enum issue with MS VS C++ - 4 messages, 3 authors
http://groups.google.com/group/comp.lang.c++/t/bc3736cc883fcf53?hl=en
* More C++ 11 questions regarding array - 4 messages, 4 authors
http://groups.google.com/group/comp.lang.c++/t/28c60ed4660dfce6?hl=en
* String and interfacing with functions using char* - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/a7d848d28878a317?hl=en
* Array Size - 1 messages, 1 author
http://groups.google.com/group/comp.lang.c++/t/a6377bc32796137b?hl=en
* Follow-up Pimpl question - 4 messages, 4 authors
http://groups.google.com/group/comp.lang.c++/t/c4cad0c102a54739?hl=en
* Function for arrays - 2 messages, 2 authors
http://groups.google.com/group/comp.lang.c++/t/466519b3df961798?hl=en
* What to C++ 11 features to cover in my C++ courses? - 3 messages, 3 authors
http://groups.google.com/group/comp.lang.c++/t/351a8b3595621c91?hl=en
==============================================================================
TOPIC: A simpler Pimpl Idiom ?
http://groups.google.com/group/comp.lang.c++/t/8c62d669bf4e1562?hl=en
==============================================================================
== 1 of 4 ==
Date: Mon, Oct 21 2013 9:45 am
From: Tobias Müller
Tobias Müller <troplin@bluewin.ch> wrote:
> mathieu <mathieu.malaterre@gmail.com> wrote:
>> I have been reading "The Joy of Pimpls " [1], but this seems
>> over-complicated IMHO. It requires a "back-pointer" just to split object in halves.
>>
>> I am thinking of providing something similar (at least in my scenario),
>> where I can hide the implementation completely.
>>
>> I am thinking in something like this:
>>
>> $ cat demo.cxx
>> // public stuff:
>> #include <iosfwd>
>>
>> struct visible
>> {
>> public:
>> void print(std::ostream & os) const;
>> protected:
>> visible(){}
>> private:
>> visible(const visible &);
>> visible & operator = (const visible &);
>> };
>>
>> visible * get_one();
>>
>> // implementation details:
>> #include <iostream>
>>
>> struct not_visible : public visible
>> {
>> public:
>> not_visible(int t, const char *v):tag(t),data(v){}
>> void print_impl(std::ostream & os) const
>> {
>> os << tag << " -> " << data << std::endl;
>> }
>> private:
>> int tag;
>> std::string data;
>> };
>>
>> void visible::print(std::ostream & os) const
>> {
>> static_cast<const not_visible*>(this)->print_impl(os);
>> }
>>
>> visible * get_one()
>> {
>> // dummy implementation just for the demo:
>> static not_visible v(123,"hello");
>> visible *ptr = &v;
>> return ptr;
>> }
>>
>> int main()
>> {
>> visible *u = get_one();
>> u->print(std::cout);
>> return 0;
>> }
>>
>>
>> Does anyone sees anything wrong with this implementation ? How would one
>> mark the class 'visible' an interface-only (it should not be derived in
>> user applications).
>>
>> Thanks,
>> -Mathieu
>>
>> [1] http://www.gotw.ca/publications/mill05.htm
>
> IMO, you gain nothing, while there are some major disadvantages.
>
> You gain nothing, because the client code always has to operate on
> pointers. In both cases you have one indirection.
>
> The disadvantages are:
> - You cannot use 'visible' objects as values, only pointers. With pimpl you
> can.
> - You cannot use constructors and destructors in client code, but have to
> use (factory) functions instead.
>
> If I had to deal with such an interface I would wrap it immediately in a
> class, just for those reasons. Especially for having a destructor.
Oh and even worse, there can only exist one object at a time since you are
using a static object. It is essentially a singleton.
Tobi
== 2 of 4 ==
Date: Mon, Oct 21 2013 11:23 am
From: "Alf P. Steinbach"
On 21.10.2013 15:45, mathieu wrote:
> I have been reading "The Joy of Pimpls " [1], but this seems over-complicated
> IMHO. It requires a "back-pointer" just to split object in halves.
>
> I am thinking of providing something similar (at least in my scenario), where I
> can hide the implementation completely.
>
> I am thinking in something like this:
>
> $ cat demo.cxx
> // public stuff:
> #include <iosfwd>
Good practice. :-)
> struct visible
> {
> public:
> void print(std::ostream & os) const;
> protected:
> visible(){}
> private:
> visible(const visible &);
> visible & operator = (const visible &);
> };
>
> visible * get_one();
>
> // implementation details:
> #include <iostream>
>
> struct not_visible : public visible
> {
> public:
> not_visible(int t, const char *v):tag(t),data(v){}
> void print_impl(std::ostream & os) const
> {
> os << tag << " -> " << data << std::endl;
> }
> private:
> int tag;
> std::string data;
> };
>
> void visible::print(std::ostream & os) const
> {
> static_cast<const not_visible*>(this)->print_impl(os);
> }
>
> visible * get_one()
> {
> // dummy implementation just for the demo:
> static not_visible v(123,"hello");
> visible *ptr = &v;
> return ptr;
> }
>
> int main()
> {
> visible *u = get_one();
> u->print(std::cout);
> return 0;
> }
>
>
> Does anyone sees anything wrong with this implementation ?
Every variant has its own advantages and drawbacks.
Wit the common PIMPL idiom client code can inherit the implementation of
the exposed class, i.e. client code can inherit a concrete, instantiable
class. This is lost with the abstract class idea (above). But one avoids
some indirection and dynamic allocation.
Not sure if Herb mentions this, but the main purpose of a PIMPL is to
encapsulate use of dirty or large or platform-specific (whatever)
headers. If that's not a problem, then PIMPL is usually not needed. A
main cost of PIMPL is that it requires separate compilation.
> How would one mark the class 'visible' an interface-only (it should
> not be derived in user applications).
For C++11, <url: http://en.cppreference.com/w/cpp/language/final>, using
the keyword "final".
For C++03, <url: http://www.parashift.com/c++-faq/final-classes.html>,
using a virtual base class with limited accessibility (because a virtual
base class must be constructed in the most derived class).
But consider whether there is any concrete advantage in doing that: it's
often a good idea to make the intended usage natural and easy and the
hazardous usage less easy, but (well OK it's famous last words) what
could possibly go wrong?
Cheers & hth.,
- Alf
== 3 of 4 ==
Date: Mon, Oct 21 2013 12:05 pm
From: Tobias Müller
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> wrote:
[...]
> Not sure if Herb mentions this, but the main purpose of a PIMPL is to
> encapsulate use of dirty or large or platform-specific (whatever)
> headers. If that's not a problem, then PIMPL is usually not needed. A
> main cost of PIMPL is that it requires separate compilation.
Separate compilation may be the main cost, but it's also one of the main
use case.
For software that comes only as binary + header it is convenient way for
hiding the implementation and maintaining binary compatibility.
>> How would one mark the class 'visible' an interface-only (it should
>> not be derived in user applications).
>
> For C++11, <url: http://en.cppreference.com/w/cpp/language/final>, using
> the keyword "final".
But then it is no more possible to derive 'invisible' from it neither. Or
am I missing something?
[...]
Tobi
== 4 of 4 ==
Date: Mon, Oct 21 2013 1:07 pm
From: Öö Tiib
On Monday, 21 October 2013 16:45:01 UTC+3, mathieu wrote:
> I have been reading "The Joy of Pimpls " [1], but this
> seems over-complicated IMHO. It requires a "back-pointer" just to
> split object in halves.
Additional indirection by that "back-pointer" is not as expensive as
lot of people seem to think, also it provides cheap swaps/moves for
free. So classical Pimpl is on lot of cases best thing.
If moving only private member functions to compilation-unit local
is the goal then that can be done without any pointers. I posted one way
how in March to comp.lang.c++.moderated:
header https://groups.google.com/d/msg/comp.lang.c++.moderated/GJyXgeEtAOA/PwXSG_ZGeGgJ
If you want to hide member data too AND want to get rid of that
pointer then in C++11 you can just have sufficient buffer for private
implementation in class. Verify that it is sufficient in compilation-unit
using C++11 'static_assert', 'alignas', 'alignof' and 'sizeof'.
Then you have to use placement new, explicit destructor calls and
reinterpret_cast to manage private implementation in that buffer.
Without C++11 one can use compiler extensions to achieve same (lot of
stuff in Boost have done it for decade).
IOW your implementation has numerous limitations that are not needed and
can be easily avoided. ;)
==============================================================================
TOPIC: Question regarding copy constructor
http://groups.google.com/group/comp.lang.c++/t/9e723534f9e94458?hl=en
==============================================================================
== 1 of 3 ==
Date: Mon, Oct 21 2013 10:58 am
From: Öö Tiib
On Monday, 21 October 2013 18:55:47 UTC+3, Tobias Müller wrote:
> "K. Frank" <kfrank29.c@gmail.com> wrote:
>
> [...]
>
> > Given that in somenath's example, the constructor
> > A(int) exists, and given that the compiler is
> > allowed to copy-elide the copy constructor away,
> > why does the standard _not_ define
> >
> > A a = 2;
> >
> > and
> >
> > A a(2);
> >
> > to be synonymous? That is, why not just define
> > A a = 2 to be direct initialization, and be done
> > with it?
> >
> > Given that the programmer cannot rely on the copy
> > constructor getting called in this situation, I
> > don't see any reason why letting the compiler
> > first construct and then copy construct would be
> > advantage. Wouldn't it be simpler and better (and
> > fully backward compatible) just to require A a = 2
> > to be direct initialization?
>
> Even more so as it is already a special case. Regarding only the syntax,
> you would expect the appropriate assignment operator to be called.
There certainly won't be assignment operators used in initialization. Most
coding standards suggest to write what you actually want 'A a(2);' and
to avoid writing "likely synonymous after optimizations" variants.
== 2 of 3 ==
Date: Mon, Oct 21 2013 11:42 am
From: Tobias Müller
Öö Tiib <ootiib@hot.ee> wrote:
> On Monday, 21 October 2013 18:55:47 UTC+3, Tobias Müller wrote:
>> "K. Frank" <kfrank29.c@gmail.com> wrote:
>>
>> [...]
>>
>>> Given that in somenath's example, the constructor
>>> A(int) exists, and given that the compiler is
>>> allowed to copy-elide the copy constructor away,
>>> why does the standard _not_ define
>>>
>>> A a = 2;
>>>
>>> and
>>>
>>> A a(2);
>>>
>>> to be synonymous? That is, why not just define
>>> A a = 2 to be direct initialization, and be done
>>> with it?
>>>
>>> Given that the programmer cannot rely on the copy
>>> constructor getting called in this situation, I
>>> don't see any reason why letting the compiler
>>> first construct and then copy construct would be
>>> advantage. Wouldn't it be simpler and better (and
>>> fully backward compatible) just to require A a = 2
>>> to be direct initialization?
>>
>> Even more so as it is already a special case. Regarding only the syntax,
>> you would expect the appropriate assignment operator to be called.
>
> There certainly won't be assignment operators used in initialization.
Yes, that's what I wanted to say. Syntactically it's an assignment, but in
the context of a declaration it is special cased to actually mean
initialization. But then, why in a such convoluted way?
> Most coding standards suggest to write what you actually want 'A a(2);' and
> to avoid writing "likely synonymous after optimizations" variants.
The above proposal would provide exactly that. Without relying on
optimizations.
But I agree, just writing the appropriate constructor is even better.
Tobi
== 3 of 3 ==
Date: Mon, Oct 21 2013 12:38 pm
From: Victor Bazarov
On 10/21/2013 2:42 PM, Tobias Müller wrote:
> [..] Syntactically it's an assignment, but in
> the context of a declaration it is special cased to actually mean
> initialization. But then, why in a such convoluted way?
<shrug> Why not? This is one of C legacies. It's very likely that in a
function scope it literally meant the same machine code... And many an
older folk got used to seeing this form and keep using it. Imagine (a)
requiring to rewrite millions of lines(*) of
int a = 42;
to
int a { 42 };
and (b) force scores of thousands of C++ programmers to re-learn to use
that form from some point on... I don't think it's feasible.
>> [..]
*) I don't really know how many lines of such code exist and need to be
maintained, so might be off by a billion or two.
V
--
I do not respond to top-posted replies, please don't ask
==============================================================================
TOPIC: scoped enum issue with MS VS C++
http://groups.google.com/group/comp.lang.c++/t/bc3736cc883fcf53?hl=en
==============================================================================
== 1 of 4 ==
Date: Mon, Oct 21 2013 11:37 am
From: bobl0456@gmail.com
I get the following error:
TurtleGraphics.cpp(93): error C2677: binary '!=' : no global operator found which takes type 'Cmds' (or there is no acceptable conversion)
for the following statement:
} while ( cmdsArray[cmdNo] != Cmds::END_OF_DATA ); // repeat until end of data reached
Cmds is defined as:
enum class Cmds { PEN_UP = 1, PEN_DWN, TURN_RIGHT, TURN_LEFT, MOVE, DISPLAY, END_OF_DATA = 9};
and cmdsArray is a pointer based array of type int.
I do not understand why this should not work. BTW, I know that if I change the enum back to traditional unscoped enum it will work fine.
Bob
== 2 of 4 ==
Date: Mon, Oct 21 2013 11:47 am
From: "Alf P. Steinbach"
On 21.10.2013 20:37, bobl0456@gmail.com wrote:
> I get the following error:
>
> TurtleGraphics.cpp(93): error C2677: binary '!=' : no global operator found which takes type 'Cmds' (or there is no acceptable conversion)
>
> for the following statement:
>
> } while ( cmdsArray[cmdNo] != Cmds::END_OF_DATA ); // repeat until end of data reached
>
> Cmds is defined as:
>
> enum class Cmds { PEN_UP = 1, PEN_DWN, TURN_RIGHT, TURN_LEFT, MOVE, DISPLAY, END_OF_DATA = 9};
>
> and cmdsArray is a pointer based array of type int.
>
> I do not understand why this should not work.
Using the word "class" you asked for a bit stronger type checking.
You got it.
> BTW, I know that if I change the enum back to traditional unscoped enum it will work fine.
Instead, fix the array type.
Cheers & hth.,
- Alf
PS: Using ALL UPPERCASE for constants is a Java convention. In C++ ALL
UPPERCASE is conventionally reserved for macro names, in order to reduce
the chance of name collisions and unintended text substitution. Java
doesn't have macros. Using such names for mere constants, as in Java, in
C++ increases the chance of name collisions and unintended text
substitution, i.e. it's /directly in conflict/ with the common C++
convention. It's also an all out visual attack, hurting the eyes. And
ears. :(
== 3 of 4 ==
Date: Mon, Oct 21 2013 12:02 pm
From: kfrank29.c@gmail.com
Hi Bob!
I can't comment specifically on the microsoft compiler,
but it appears to be acting according to the standard.
On Monday, October 21, 2013 2:37:06 PM UTC-4, bobl...@gmail.com wrote:
> I get the following error:
>
> TurtleGraphics.cpp(93): error C2677: binary '!=' : no global operator found which takes type 'Cmds' (or there is no acceptable conversion)
>
> for the following statement:
>
> } while ( cmdsArray[cmdNo] != Cmds::END_OF_DATA ); // repeat until end of data reached
>
> Cmds is defined as:
>
> enum class Cmds { PEN_UP = 1, PEN_DWN, TURN_RIGHT, TURN_LEFT, MOVE, DISPLAY, END_OF_DATA = 9};
>
> and cmdsArray is a pointer based array of type int.
>
> I do not understand why this should not work. BTW, I know that if I change the enum back to traditional unscoped enum it will work fine.
The key issue is that enum classes (scoped enums)
in c++11 do not implicitly convert to ints (unlike
"traditional" enums).
Let me quote from Stroustrup's (very useful) c++11 faq:
http://www.stroustrup.com/C++11FAQ.html#enum
The enum classes ("new enums", "strong enums") address
three problems with traditional C++ enumerations:
conventional enums implicitly convert to int, causing errors
when someone does not want an enumeration to act as an integer.
So, this is a feature (that I almost agree with), not
a bug.
Also not the further comment in the faq:
In the standard library, enum classes are used
...
Several of these have operators, such as == defined.
Reading between the lines a little here you can make
it possible to test your enum class against an int for
equality or inequality, but to do so you have to provide
your own operator==() and/or operator!=().
(But following Alf's suggestion, probably the most direct
fix to your current issue is to make cmdsArray an array
of Cmds rather than int.
> Bob
Happy C++11 Hacking!
K. Frank
== 4 of 4 ==
Date: Mon, Oct 21 2013 1:17 pm
From: bobl0456@gmail.com
Thanks for the responses.
Bob
==============================================================================
TOPIC: More C++ 11 questions regarding array
http://groups.google.com/group/comp.lang.c++/t/28c60ed4660dfce6?hl=en
==============================================================================
== 1 of 4 ==
Date: Mon, Oct 21 2013 12:35 pm
From: bobl0456@gmail.com
Correct me if I am wrong, but there seems to be a least 2 short comings (at least to my view point) to using std::array :
1) no equivalent to
int myArray[] = { a very long list of values too long to conveniently count };
2) no equivalent to
void func (int[], int[][3] );
in other words, when converted to an std::array we need to specify the size of all of the dimensions of arrays passed to a function.
Am I correct on these 2 points? Or are there acceptable workarounds or syntax I am not aware of?
Thanks,
Bob
== 2 of 4 ==
Date: Mon, Oct 21 2013 1:29 pm
From: Öö Tiib
On Monday, 21 October 2013 22:35:43 UTC+3, bobl...@gmail.com wrote:
> Correct me if I am wrong, but there seems to be a least 2 short comings (at least to my view point) to using std::array :
>
> 1) no equivalent to
> int myArray[] = { a very long list of values too long to conveniently count };
Correct. That is the sole shortcoming and such long arrays are rare and
usually immutable.
> 2) no equivalent to
>
> void func (int[], int[][3] );
Wrong. That declaration is /exactly/ equivalent to:
void func (int*, int(*)[3]);
No arrays are passed there, just pointers. 'std::array' can be converted
to pointer to underlying array with 'data()' but why? Just pass pointer
to 'std::array'.
> in other words, when converted to an std::array we need to specify the
> size of all of the dimensions of arrays passed to a function.
If the function does not know the dimensions then how can it dare to
touch the elements of array? Unsafe "hopefully it is OK"? That is common
source of errors. If it does know it then what is the problem to
indicate it in interface? If it should accept different arrays then
it can be made a template and if the arrays are made dynamically
then it is 'std::vector' (not 'std::array') that you need instead
anyway.
== 3 of 4 ==
Date: Mon, Oct 21 2013 1:33 pm
From: red floyd
On 10/21/2013 12:35 PM, bobl0456@gmail.com wrote:
> Correct me if I am wrong, but there seems to be a least 2 short comings (at least to my view point) to using std::array :
>
> 1) no equivalent to
>
> int myArray[] = { a very long list of values too long to conveniently count };
Not sure about this. I think you may need to know the size for the
template parameter.
>
> 2) no equivalent to
>
> void func (int[], int[][3] );
template<int N>
void func(std::array<int, N>, std::array<std::array<int, N>,3>);
== 4 of 4 ==
Date: Mon, Oct 21 2013 1:36 pm
From: "Alf P. Steinbach"
On 21.10.2013 21:35, bobl0456@gmail.com wrote:
> Correct me if I am wrong, but there seems to be a least 2 short comings (at least to my view point) to using std::array :
>
> 1) no equivalent to
>
> int myArray[] = { a very long list of values too long to conveniently count };
It's not difficult to work around, but it's definitely missing
functionality.
E.g. see my clc++ posting <url:
news:a12f9f2e-e414-45e8-9210-1f0543ffaa5c@googlegroups.com>, e.g. as
archived at
<url:
https://groups.google.com/d/msg/comp.lang.c++/0gGpBl6Bm54/3_tjMwXf2J0J>.
Which Visual C++ ICE reminds me to submit yet another bug report to
Microsoft. I just plain forgot about it. Also, reminds me of how Google
actively sabotages Usenet: in addition to dropped references, sabotage
of signature marker (you can't -- or couldn't -- post one via GG), no
threaded display, etc., Google Groups posts with QUOTED PRINTABLE. :(
> 2) no equivalent to
>
> void func (int[], int[][3] );
>
> in other words, when converted to an std::array we need to specify the size of all
> of the dimensions of arrays passed to a function.
Hm.
> Am I correct on these 2 points? Or are there acceptable workarounds or syntax I
> am not aware of?
For initialization, see above.
Cheers & hth.,
- Alf
==============================================================================
TOPIC: String and interfacing with functions using char*
http://groups.google.com/group/comp.lang.c++/t/a7d848d28878a317?hl=en
==============================================================================
== 1 of 1 ==
Date: Mon, Oct 21 2013 12:57 pm
From: Seungbeom Kim
On 2013-10-20 09:04, James Kanze wrote:
>
> IIRC, emacs has a block mode which allows text insertion at
> logical positions where there is no text; it fills with blanks
> if needed. One of the few things I don't like about vim is that
> even in visual block mode, the visual cursor cannot be placed
> beyond the physical end of line.
Have you tried "set virtualedit=..." in Vim?
It seems to work exactly in the way you described for Emacs above.
--
Seungbeom Kim
==============================================================================
TOPIC: Array Size
http://groups.google.com/group/comp.lang.c++/t/a6377bc32796137b?hl=en
==============================================================================
== 1 of 1 ==
Date: Mon, Oct 21 2013 1:43 pm
From: Seungbeom Kim
On 2013-06-22 09:44, Leigh Johnston wrote:
>
> Bad engineering practice my arse; you simply use a cast in the
> appropriate place and if you forget to cast and are using abs then the
> compiler will complain:
>
> int main()
> {
> typedef unsigned int length_t;
> typedef int difference_t;
> length_t a = 42;
> length_t b = 2;
> std::cout << "42 - 2 = " << abs(static_cast<difference_t>(a - b)) << std::endl;
> std::cout << "2 - 42 = " << abs(static_cast<difference_t>(b - a)) << std::endl;
> }
This relies on the implementation-defined conversion to a signed
integral type of an out-of-range value. The proper way is:
abs(static_cast<difference_t>(a) - static_cast<difference_t>(b))
assuming, of course, that a and b are in the range for difference_t.
--
Seungbeom Kim
==============================================================================
TOPIC: Follow-up Pimpl question
http://groups.google.com/group/comp.lang.c++/t/c4cad0c102a54739?hl=en
==============================================================================
== 1 of 4 ==
Date: Mon, Oct 21 2013 3:39 pm
From: Rupert Swarbrick
I'm coming back to writing some C++ after a few years in Lisp-land, and
was wondering about the "pimpl idiom". I understand how to write and use
it, and have done in the past. However, I don't really understand what
it gains you over having an abstract base class in the header, along
with a factory function.
Presumably there's a significant difference, since people put up with
the reams of boilerplate required for passing functions through to the
implementation object. Can anyone explain to me what it is?
Rupert
PS: I'm not sure whether there are strong feelings about whether to use
this idiom or not. To be clear, I'm not trying to hear them! I can
see obvious downsides to keeping a pointer to an implementation
object (verbosity; have to be careful about destructor +
exceptions...) and I'm interested to know what the upsides are.
== 2 of 4 ==
Date: Mon, Oct 21 2013 6:07 pm
From: "K. Frank"
Hello Rupert!
On Monday, October 21, 2013 6:39:27 PM UTC-4, Rupert Swarbrick wrote:
> I'm coming back to writing some C++ after a few years in Lisp-land, and
> was wondering about the "pimpl idiom". I understand how to write and use
> it, and have done in the past. However, I don't really understand what
> it gains you over having an abstract base class in the header, along
> with a factory function.
>
> Presumably there's a significant difference, since people put up with
> the reams of boilerplate required for passing functions through to the
> implementation object. Can anyone explain to me what it is?
Well, first off, as you recognize, there is cost to
using the pimpl idiom, and I certainly won't argue
that it is always desirable of preferable.
However, one benefit is that for some use cases
constructors and destructors are very useful tools.
In particular they let you have local instances of
classes on the stack and those instances get cleaned
up automatically -- their destructors called -- when
they go out scope, even if scope is exited because
an exception was thrown. This is the main reason
that RAII plus executions / stack unwinding is so
powerful.
Of course there are other ways of achieving this.
For example you could use a smart pointer and a
factory function (but one might argue that doing
so is just reimplementing the pimpl idiom by another
name).
> Rupert
> ...
Good luck.
K. Frank
== 3 of 4 ==
Date: Mon, Oct 21 2013 7:36 pm
From: Öö Tiib
On Tuesday, 22 October 2013 01:39:27 UTC+3, Rupert Swarbrick wrote:
> I'm coming back to writing some C++ after a few years in Lisp-land, and
> was wondering about the "pimpl idiom". I understand how to write and use
> it, and have done in the past. However, I don't really understand what
> it gains you over having an abstract base class in the header, along
> with a factory function.
We call it "pimpl" since we like Orcish language perhaps, rest call it
"Cheshire Cat", "Compiler firewall" or "Bridge pattern".
There is better separation of concerns. Abstraction implements external
interface. Implementor implements internal implementation.
There are more dynamics. For example when object behind pointer to
interface is made then it can not change its type anymore in C++.
The implementor that is behind abstraction of pimpl however may be
is dynamically replaced, shared, cached, reused or copied-on-write etc.
by abstraction. It is not business of user of abstraction but
externally it may feel like type has changed entirely during life-time
of abstraction.
Slight performance advantage of pimpl is that the virtual functions
are not needed. There may be virtual functions as implementor may be
polymorphic ... but those are not mandatory. So virtual functions
may be used when those improve performance, not when they describe
common interface.
> Presumably there's a significant difference, since people put up with
> the reams of boilerplate required for passing functions through to the
> implementation object. Can anyone explain to me what it is?
It is never clear if any of named advantages is substantial enough for
you.
> PS: I'm not sure whether there are strong feelings about whether to use
> this idiom or not. To be clear, I'm not trying to hear them! I can
> see obvious downsides to keeping a pointer to an implementation
> object (verbosity; have to be careful about destructor +
> exceptions...) and I'm interested to know what the upsides are.
I must say that pimpl has its downsides too. If the problem has simple
solution then it is easy to make it more complex by adding unneeded
pimpl. We should aim to keep things as simple as possible (just not
simpler than possible). So pimpl is good for complex enough objects.
== 4 of 4 ==
Date: Mon, Oct 21 2013 10:41 pm
From: Tobias Müller
Rupert Swarbrick <rswarbrick@gmail.com> wrote:
> I'm coming back to writing some C++ after a few years in Lisp-land, and
> was wondering about the "pimpl idiom". I understand how to write and use
> it, and have done in the past. However, I don't really understand what
> it gains you over having an abstract base class in the header, along
> with a factory function.
>
> Presumably there's a significant difference, since people put up with
> the reams of boilerplate required for passing functions through to the
> implementation object. Can anyone explain to me what it is?
>
>
> Rupert
>
>
> PS: I'm not sure whether there are strong feelings about whether to use
> this idiom or not. To be clear, I'm not trying to hear them! I can
> see obvious downsides to keeping a pointer to an implementation
> object (verbosity; have to be careful about destructor +
> exceptions...) and I'm interested to know what the upsides are.
IMO the abstract base class pattern is not the right solution for this
problem. It may work as long as your objects are only given out, and never
taken back.
As soon as you have a method taking the abstract base class as parameter it
is not safe anymore.
While the method is formally taking an abstract base class, it actually
expects your concrete subclass instead (and must resort to casting).
I know no way for restricting a class to only be derived once. There is
nothing (except documentation) that prevents the client code from deriving
from your abstract base class and pass such an object to your method.
It is just an incomplete solution to the problem. OTOH, pimpl objects
behave like normal C++ objects in every single aspect. As long as you
restrict yourself to the public interface you could use the pimpl class as
a drop-in replacement of the actual implementation.
Tobi
==============================================================================
TOPIC: Function for arrays
http://groups.google.com/group/comp.lang.c++/t/466519b3df961798?hl=en
==============================================================================
== 1 of 2 ==
Date: Mon, Oct 21 2013 7:45 pm
From: axcytz@gmail.com
Hi all,
I have an array containing 10 elements in it. I want to swap all elements (2 swap) with each other after each swap I will calculate a function value based on the updated array. So, I will have 45 different function values (10 choose 2). I will store these values in another array and will get the index of the smallest valued array.
This is what i want to do.
include<algortihm>
My function:
for(int i=0 ; i< 45; i++)
{
for(int j=0; j<10; j++)
{
for(int k=0; k<10; k++)
{
UpdatedArray[i] = swap(MyArray[j], MyArray[k]);
FunctionValue[i] = Data[k]*Value[UpdatedArray]; //here the part after equal sign is not important for now.
}
}
}
Any help is appreciated, thanks!
== 2 of 2 ==
Date: Mon, Oct 21 2013 8:50 pm
From: "Alf P. Steinbach"
On 22.10.2013 04:45, axcytz@gmail.com wrote:
>
> I have an array containing 10 elements in it. I want to swap all elements
> (2 swap) with each other after each swap I will calculate a function value
> based on the updated array. So, I will have 45 different function values
> (10 choose 2). I will store these values in another array and will get the
> index of the smallest valued array.
OK so far.
This implies that you store information about which items were swapped.
> This is what i want to do.
>
> include<algortihm>
>
> My function:
>
>
> for(int i=0 ; i< 45; i++)
> {
> for(int j=0; j<10; j++)
> {
> for(int k=0; k<10; k++)
> {
> UpdatedArray[i] = swap(MyArray[j], MyArray[k]);
> FunctionValue[i] = Data[k]*Value[UpdatedArray]; //here the part after equal sign is not important for now.
>
> }
> }
> }
>
> Any help is appreciated, thanks!
Well the code above does NOT do what you described. It performs 4500
swaps, not 45. It swaps each pair twice. And it doesn't store the
function results.
To gain some clarity,
1. Reduce the array size to, say, 4. Which you can handle manually.
2. Think about how to do those swaps, systematically, BY HAND.
It's the system that's important.
But it's also important to actually try it out, by hand.
3. When you have managed to do it by hand (e.g. using small paper
squares to represent the array items), then try to express it in C++.
At that point it's time to perhaps post a new question here, or if
everything's clear, just proceed directly to computing and storing
function results.
Cheers & hth.,
- Alf (hoping that nobody will spoil your learning experience by posting
code showing how clever they are (not!), & wishing good luck)
==============================================================================
TOPIC: What to C++ 11 features to cover in my C++ courses?
http://groups.google.com/group/comp.lang.c++/t/351a8b3595621c91?hl=en
==============================================================================
== 1 of 3 ==
Date: Mon, Oct 21 2013 8:18 pm
From: bobl0456@gmail.com
Hi folks,
I am finally covering some of the new C++ features in my C++ course. I am interested in getting input from the C++ community as to the priority of new features to cover.
To give you some idea of the features I am planning to cover, these are some of the new features I plan to cover:
array container
auto for type inference
delegating ctors
explicit conversion operators
final classes
final member functions
inheriting base class ctors
list initialization changes
move assignment operator
move ctor
non-deterministic random number generation
nullptr
override keyword
range based for statement
regular expressions
rvalue references
scoped enums
shared_ptr smart pointer
unique_ptr smart pointer
weak_ptr smart pointer
I would appreciate advice on additional features I should cover and any of the above features you feel are unimportant.
TIA
Bob
== 2 of 3 ==
Date: Mon, Oct 21 2013 8:36 pm
From: "Alf P. Steinbach"
On 22.10.2013 05:18, bobl0456@gmail.com wrote:
> Hi folks,
>
> I am finally covering some of the new C++ features in my C++ course. I am interested in getting input from the C++ community as to the priority of new features to cover.
>
> To give you some idea of the features I am planning to cover, these are some of the new features I plan to cover:
>
> array container
> auto for type inference
> delegating ctors
> explicit conversion operators
> final classes
> final member functions
> inheriting base class ctors
> list initialization changes
> move assignment operator
> move ctor
> non-deterministic random number generation
> nullptr
> override keyword
> range based for statement
> regular expressions
> rvalue references
> scoped enums
> shared_ptr smart pointer
> unique_ptr smart pointer
> weak_ptr smart pointer
>
> I would appreciate advice on additional features I should cover and any of the above
> features you feel are unimportant.
The students should already be familiar with shared_ptr from their
experience with C++03, using boost::shared_ptr and/or the TR1 shared_ptr.
If not then you need to cover that first, it's C++03 stuff.
Then unique_ptr (pure C++11) as replacement for now deprecated auto_ptr.
That covers the most important FUNCTIONAL CHANGES of the language, how
to manage dynamically allocated objects.
Then, considering what I use most,
1. "auto" (especially for function declarations and constants),
2. rvalue references and move semantics with std::move, move
constructors and move assignment, and new conventions for argument
passing (by value is often very OK) and function results (not const)
3. std::function and lambdas
I use range-based loops all the time but if you have to choose, then as
above.
As a general guideline, use the teaching time on what the students need
to understand and can benefit from discussing, don't waste that time on
what they can simply read up in Wikipedia, blogs and the holy Standard
-- or MSDN Library -- even if a buzzword checklist might impress. ;-)
Cheers & hth.,
- Alf
== 3 of 3 ==
Date: Mon, Oct 21 2013 9:24 pm
From: woodbrian77@gmail.com
On Monday, October 21, 2013 10:18:23 PM UTC-5, bobl...@gmail.com wrote:
> Hi folks,
>
>
>
> I am finally covering some of the new C++ features in my C++ course. I am interested in getting input from the C++ community as to the priority of new features to cover.
>
>
>
> To give you some idea of the features I am planning to cover, these are some of the new features I plan to cover:
>
>
>
> array container
> auto for type inference
> delegating ctors
> list initialization changes
> move assignment operator
> move ctor
> nullptr
> range based for statement
> rvalue references
> scoped enums
> unique_ptr smart pointer
>
I use the above and also use non-static data member
initialization. I haven't come across the need for
shared_ptr. I haven't used explicit conversion
operator's, but am interested in learning about
that.
Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net
==============================================================================
You received this message because you are subscribed to the Google Groups "comp.lang.c++"
group.
To post to this group, visit http://groups.google.com/group/comp.lang.c++?hl=en
To unsubscribe from this group, send email to comp.lang.c+++unsubscribe@googlegroups.com
To change the way you get mail from this group, visit:
http://groups.google.com/group/comp.lang.c++/subscribe?hl=en
To report abuse, send email explaining the problem to abuse@googlegroups.com
==============================================================================
Google Groups: http://groups.google.com/?hl=en
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment