- pimpl <--> polymorphism - 1 Update
- wording: "references cannot be null" - 6 Updates
- Quick Question - functors via structs - 4 Updates
- The members of ::std::initializer_list - 2 Updates
- operator[][] - 2 Updates
- operator[][] - 1 Update
- Does C++ have "argument value optimization"? - 1 Update
"Norman J. Goldstein" <normvcr@telus.net>: May 06 04:09PM -0700 I was thinking of which situations are better to use pimpl or polymorhphism. Both options allow hiding the implementation, so that the main class does not need to be recompiled, should the implementation change. Certainly, polymorphism is the C++ elegant approach, but does require a static/global method to create new instances of the main class. Both approaches require indirection to access the implementation, and require storing an extra pointer to do that (polymorphism has the pointer to the vtable). The defining difference between the two approaches seems to be that with pimpl, you can, at run time, switch to a different implementation while keeping the same main class. I conclude that there is no point using pimpl unless you want to do "hot" switching of implementations. Other opinions about this? Here is code that prints "hello" using both pimpl and polymorphism. ///////////////////////// PIMPL //////////////////// class ImplPimpl; class MainPimpl { public: MainPimpl( void ); ~MainPimpl(); void hello( void ); private: ImplPimpl* impl_; }; #include <iostream> using namespace std; class ImplPimpl { friend class MainPimpl; void hello( void ) { cout << "ImplPimpl hello" << endl; } }; MainPimpl::MainPimpl( void ) : impl_( new ImplPimpl ) {} MainPimpl::~MainPimpl( void ) { delete impl_; impl_ = nullptr; } void MainPimpl::hello( void ) {impl_->hello(); } ////////////////// POLYMORPHISM ////////////////// class MainPoly { public: virtual ~MainPoly(){}; virtual void hello( void ) = 0; static MainPoly* create( void ); }; class ImplPoly : public MainPoly { void hello( void ) { cout << "ImplPoly hello" << endl; } }; MainPoly* MainPoly::create( void ) { return new ImplPoly; } //////////////////////////////////////////////// #include <memory> int main( int argc, char* argv[] ) { unique_ptr< MainPimpl > pimpl( new MainPimpl ); pimpl->hello(); unique_ptr< MainPoly > poly( MainPoly::create() ); poly->hello(); return 0; }// main |
Juha Nieminen <nospam@thanks.invalid>: May 06 08:45AM > Saying, »q is not null«, when in fact »q == 0« /is/ true, is something > that can be understood by all those who can guess what the intended > meaning is, but might not be true by a strict reading of the wording. That's like saying that an int& is "null" if the int it references happens to have the value 0. The reference is not null. The value it points to might be. --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
drew@furrfu.invalid (Drew Lawson): May 06 06:27PM In article <references-20150505172123@ram.dialup.fu-berlin.de> > When asked for the difference between pointers and references > some say that references cannot be null. If you say so. What normally hear is some variation of "references must be bound to an object." -- Drew Lawson | It's not enough to be alive | when your future's been deferred |
legalize+jeeves@mail.xmission.com (Richard): May 06 06:55PM [Please do not mail me a copy of your followup] drew@furrfu.invalid (Drew Lawson) spake the secret code >> some say that references cannot be null. >If you say so. What normally hear is some variation of "references >must be bound to an object." Every time I've asked the question in an interview, noone knew the answer. Rather than being pedantic about the form of their answer, I would simply accept anything that indicated that they knew that you don't need to check references to see if they refer to something. -- "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> |
Melzzzzz <mel@zzzzz.com>: May 06 09:18PM +0200 On Wed, 6 May 2015 18:55:42 +0000 (UTC) > answer. Rather than being pedantic about the form of their answer, I > would simply accept anything that indicated that they knew that you > don't need to check references to see if they refer to something. How would you check reference too see if they refer to something? |
Victor Bazarov <v.bazarov@comcast.invalid>: May 06 04:29PM -0400 On 5/6/2015 3:18 PM, Melzzzzz wrote: >> would simply accept anything that indicated that they knew that you >> don't need to check references to see if they refer to something. > How would you check reference too see if they refer to something? In good ol' times, when everybody simply ignored UB, checking a null reference was done by comparing the address of the object with 0. Same with 'this' ('coz sometimes it just was "necessary to call a member function for a non-existent object"): void foo(sometype &ref) { if (&ref != NULL) ... } or void sometype::foo() { if (this != NULL) ... How else? :-) Of course, the biggest problem was uninitialized pointers (not null ones) which in the worst case would point to some random place in valid memory, and references that were initialized by indirection from such pointers. V -- I do not respond to top-posted replies, please don't ask |
legalize+jeeves@mail.xmission.com (Richard): May 06 09:25PM [Please do not mail me a copy of your followup] Melzzzzz <mel@zzzzz.com> spake the secret code >> would simply accept anything that indicated that they knew that you >> don't need to check references to see if they refer to something. >How would you check reference too see if they refer to something? You can't. That is what indicates that they understand the difference between a reference and a pointer. If they think references are just pointers with . syntax instead of -> syntax, it means they don't understand references. -- "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> |
Doug Mika <dougmmika@gmail.com>: May 06 09:40AM -0700 Well, I think I'm beginning to understand all of this, but there is one more thing that is peculiar. If in my map object instantiation I specify a type for the sort algorithm, then why don't I have to include the sort functor or sort function pointer in the constructor? ie. In the following program the map object called "fourth" has in it's type template parameter the type for classcomp, but doesn't include an instance of classcomp in its constructor. Which sort algorithm will fourth use: the one originally provided by std::map or classcomp::operator()? // constructing maps #include <iostream> #include <map> bool fncomp (char lhs, char rhs) {return lhs<rhs;} struct classcomp { bool operator() (const char& lhs, const char& rhs) const {return lhs<rhs;} }; int main () { std::map<char,int> first; first['a']=10; first['b']=30; first['c']=50; first['d']=70; std::map<char,int> second (first.begin(),first.end()); std::map<char,int> third (second); std::map<char,int,classcomp> fourth; // class as Compare bool(*fn_pt)(char,char) = fncomp; std::map<char,int,bool(*)(char,char)> fifth (fn_pt); // function pointer as Compare return 0; } |
legalize+jeeves@mail.xmission.com (Richard): May 06 05:53PM [Please do not mail me a copy of your followup] Doug Mika <dougmmika@gmail.com> spake the secret code >more thing that is peculiar. If in my map object instantiation I >specify a type for the sort algorithm, then why don't I have to include >the sort functor or sort function pointer in the constructor? The answer is obtained by looking at the declarations for the constructors of std::map: <http://en.cppreference.com/w/cpp/container/map/map> Every place where the constructor accepts an instance of the comparison function, the default value for this argument is Compare(), a default constructed instance of your comparison type supplied in the template argument. -- "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> |
Victor Bazarov <v.bazarov@comcast.invalid>: May 06 02:40PM -0400 On 5/6/2015 12:40 PM, Doug Mika wrote: > Well, I think I'm beginning to understand all of this, but there is one more thing that is peculiar. If in my map object instantiation I specify a type for the sort algorithm, then why don't I have to include the sort functor or sort function pointer in the constructor? If you don't supply a particular function, what's going to happen? Case 1: the comparator is a class with operator() defined. If you don't supply an object, it will be default-constructed from that type. What does it mean to default-construct an object? If all that type does is to use its op(), i.e. if the object has no *state*, who cares? It's still going to be fine, a default-constructed object will be called to compare your objects (keys), i.e. an empty instance of the class will work hard [by means of its operator() member function] to successfully compare what needs to be compared. All is well. Case 2: the comparator is a function [pointer]. If you don't supply any specific function, it will be default-constructed from that type (a pointer to a function). What does it mean to default-construct a pointer? What value will it have? What *code* will be behind that pointer? It will be a _null_ pointer, IOW, a non-existent function. Can *that* be used to compare your objects? Not going to work. That is why when you specify a class (with an overloaded op() member), you're pretty much done, unless you need a special state, which you can give it at the construction time (less frequent). But when you specify that "my comparator is a function that takes two references to int and returns a bool", the compiler is not going to invent that function for you. > std::map<char,int,bool(*)(char,char)> fifth (fn_pt); // function pointer as Compare > return 0; > } V -- I do not respond to top-posted replies, please don't ask |
Paavo Helde <myfirstname@osa.pri.ee>: May 06 01:58PM -0500 Doug Mika <dougmmika@gmail.com> wrote in > one more thing that is peculiar. If in my map object instantiation I > specify a type for the sort algorithm, then why don't I have to > include the sort functor or sort function pointer in the constructor? The constructor parameter has a default value, namely the default value of the given comparator type. In the functor variant, this is the default-constructed functor, which is OK for simple functors which do not need any extra data. In the function pointer variant, the default value would be a NULL pointer, which obviously would not be very useful. Thus you need to pass the pointer explicitly (and in your code actually have done so). So, the functor style is more readable, more flexible, more optimizable and provides some sensible defaults. IOW, it just fits better with the templated STL code. I guess the function pointer variant is mainly supported for smoother upgrade path for C programmers used to qsort(). > include an instance of classcomp in its constructor. Which sort > algorithm will fourth use: the one originally provided by std::map or > classcomp::operator()? The latter. There is no algorithm "provided originally" by std::map, because std::map is a template, not a class, and the default algorithm (std::less) appears just as the default choice for some template argument. The compiler will generate the actual class code from this template, based on the template arguments. As you have replaced the default template argument std::less with your classcomp, then the generated class code for this instantiation has no idea that std::less exists, not to speak about using or calling it somehow. |
Juha Nieminen <nospam@thanks.invalid>: May 06 08:41AM > Besides, the rationales behind language design decisions are discussed > in comp.std.c++. Consider posting there, if you are really interested > and not just venting some kind of frustration, OK? Dispersing conversation about the same topic (ie. C++) into several groups doesn't help anybody. It's not like this group gets thousands of posts every day and there's need to alleviate the flooding. --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
Victor Bazarov <v.bazarov@comcast.invalid>: May 06 09:05AM -0400 On 5/6/2015 4:41 AM, Juha Nieminen wrote: > Dispersing conversation about the same topic (ie. C++) into several > groups doesn't help anybody. It's not like this group gets thousands > of posts every day and there's need to alleviate the flooding. Welcome back! I've missed you. It's not the same newsgroup without you. V -- I do not respond to top-posted replies, please don't ask |
Nobody <nobody@nowhere.invalid>: May 06 08:48AM +0100 On Tue, 05 May 2015 15:00:38 -0700, asetofsymbols wrote: > Is it possible to define operator operator[][]? > (and operator[][][] and operator[][][][]) No. But you can define operator[] such that its return type supports subscripting (either a pointer or a class which itself implements operator[]). Alternatively, you could use operator() for array acess, so a[i][j][k] becomes a(i,j,k). |
Juha Nieminen <nospam@thanks.invalid>: May 06 08:47AM > T& operator[](int i) > {} > Seems the only that compile To achieve that syntax, T must be something that itself supports operator[]. It's perfectly possible, you just have to define it more recursively. --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
ram@zedat.fu-berlin.de (Stefan Ram): May 06 12:23AM >asetofsymbols@gmail.com writes: >>What does it mean s{}? >In this case, it means, "an instance of s". In »struct s{};«, it means that the type is empty, in »int s{};« it requests »s« to be value-initialized. As an expression, it's everything but a »functional notation«, yet it's called »functional notation type conversion«. |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: May 06 01:14AM +0100 On Tue, 05 May 2015 19:52:03 +0200 > If f might want to pass the reference on to some other function, > perhaps > g(std::forward<std::string>(s)); That is not how std::forward is intended to be used: std::forward is expected to be given a deduced type as its template parameter. The expression 'std::forward<std::string>(s)' would just convert the lvalue 's' to a rvalue - in other words, it would be identical in effect to 'std::move(s)', which is a shorter and more comprehensible way of writing it, if that is what is actually intended. With respect to the OP's question about whether binding a temporary to a function argument comprising a value std::string parameter will prompt copy elision similar to RVO, the answer is no. Copy elision of objects with non-trivial copy constructors and/or non-trivial destructors is not permitted in that case. RVO only applies to function return values. Chris |
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:
Post a Comment