- Dependecy Injection - 9 Updates
- Does the function below show undefined behavior? - 8 Updates
- Does the function below show undefined behavior? - 1 Update
- Idiots (reprise) - 1 Update
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Dec 11 07:46PM On 11/12/2015 19:02, Tobias Müller wrote: > That's exactly how allocators work for the standard containers. > Just imagine you had to pass an allocator instance to every container you > use. I am well aware of how allocators work; obviously I was referring to the use of policy based design in general (in client code) rather than in the use of third-party library code. Concrete instantiations of class templates isn't really in the spirit of dependency inversion the fundamental principle of which is to only have dependencies on abstractions rather than on concretions. > and you can use default arguments. > You don't pay for it if you don't use it (explicitly). Both syntactically > and performance wise. Yes as I said I am well aware of the performance benefits of policy based design in C++ but this is orthogonal to dependency inversion sausages. /Flibble |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 11 07:48PM On Fri, 11 Dec 2015 19:02:14 -0000 (UTC) > overhead and you can use default arguments. > You don't pay for it if you don't use it (explicitly). Both > syntactically and performance wise. True, but then every class in which a dependency is injected becomes a different type. That's OK but it is viral - everything becomes a templated class if you are not careful. The template policy pattern as popularized by Andrei Alexandrescu is a form of dependency injection but not as Christoper Pisz's .NET colleagues know it. (With apologies to what was apparently never actually said in Star Trek.) You can have default arguments for dynamic dependency injection as well, depending on how you implement it. Chris |
"Tobias Müller" <troplin@bluewin.ch>: Dec 11 08:22PM >> and performance wise. > Yes as I said I am well aware of the performance benefits of policy > based design in C++ but this is orthogonal to dependency inversion sausages. Well, policy based design _is_ a form DI and apparently it has some advantages over runtime DI, notably performance. Default arguments are probably not appropriate if you want to use DI everywhere, but still nice if you're writing an API that may be used by others that don't want to use DI. Tobi |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Dec 11 09:47PM On 11/12/2015 20:22, Tobias Müller wrote: > Default arguments are probably not appropriate if you want to use DI > everywhere, but still nice if you're writing an API that may be used by > others that don't want to use DI. You need to think about what you then do with the concrete class you have created using policy based design: void foo1(Bar<Policy1, Policy2>& r); versus void foo2(IBar& r); void foo3(IPolicy1& r); void foo4(IPolicy2& r); Function 'foo1' has a dependency on a concrete class whilst functions 'foo2', 'foo3' and 'foo4' only have dependencies on abstractions. These functions could just as well be constructors for another dependent class. Can you see now how C++ policy based design is orthogonal to traditional dependency inversion sausages? /Flibble |
"Öö Tiib" <ootiib@hot.ee>: Dec 11 01:52PM -0800 On Friday, 11 December 2015 21:49:04 UTC+2, Chris Vine wrote: > True, but then every class in which a dependency is injected becomes a > different type. That's OK but it is viral - everything becomes a > templated class if you are not careful. Instantiated template (even with default arguments) is like any other type. What you mean by viral? > form of dependency injection but not as Christoper Pisz's .NET > colleagues know it. (With apologies to what was apparently never > actually said in Star Trek.) Hmm. Policy pattern may be is not good example. It derives from policies. The .NET gang typically injects interface pointers. The interfaces are often to singletons. Does it sound likely that program will switch run-time to different singleton? If no then give the type of that singleton compile time as template argument and let the dependent ask for that pointer from its type. That is then most simple form of static injection. > You can have default arguments for dynamic dependency injection as > well, depending on how you implement it. Most flexible is to connect things together (very loose coupling both compile and run-time) with various "slots and signals" patterns. Mr. Flibble has (if I remember correctly) published one for C++03. It is even easier with C++11. |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Dec 11 09:57PM On 11/12/2015 21:52, Öö Tiib wrote: > compile and run-time) with various "slots and signals" patterns. Mr. > Flibble has (if I remember correctly) published one for C++03. It is > even easier with C++11. Yes I did! \o/ It is called "neosigslot" however I no longer use or maintain it due to the advent of C++ lambdas. /Flibble |
"Tobias Müller" <troplin@bluewin.ch>: Dec 11 10:14PM > functions could just as well be constructors for another dependent class. > Can you see now how C++ policy based design is orthogonal to traditional > dependency inversion sausages? You can have function templates too. I see no big difference except the increased verbosity of templates. Tobi |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Dec 11 10:25PM On 11/12/2015 22:14, Tobias Müller wrote: >> dependency inversion sausages? > You can have function templates too. > I see no big difference except the increased verbosity of templates. Resulting in the template keyword spreading like a virus in your code with a proportional increase in compilation time and binary file size. The big difference is having dependencies on abstractions rather than concretions results in looser coupling and better design sausages. /Flibble |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 11 11:12PM On Fri, 11 Dec 2015 13:52:32 -0800 (PST) > On Friday, 11 December 2015 21:49:04 UTC+2, Chris Vine wrote: > > On Fri, 11 Dec 2015 19:02:14 -0000 (UTC) > > Tobias Müller <troplin@bluewin.ch> wrote: [snip] > > becomes a templated class if you are not careful. > Instantiated template (even with default arguments) is like any other > type. What you mean by viral? Static polymorphism requires you to propagate types. That is not what is normally intended with dependency injection. But no one owns the expression so it can mean whatever you want it to mean. > > actually said in Star Trek.) > Hmm. Policy pattern may be is not good example. It derives from > policies. The .NET gang typically injects interface pointers. Which is what is normally meant by dependency injection (or the C++ or Java or ... equivalent). [snip] > compile and run-time) with various "slots and signals" patterns. Mr. > Flibble has (if I remember correctly) published one for C++03. It is > even easier with C++11. There are lots of signal/slot implementations available. I have one of my own, which provides for automatic disconnection/unsubscription on receiver or sender destruction. There are two implementations in boost. However, they are not particularly important for dependency injection as such, which is normally accomplished by simple interfaces/virtual functions/polymorphic function objects. signal/slot implementations do however permit even looser coupling, and are very useful. I use them all the time. They are perhaps closer to the command pattern but all these (strategy pattern, command pattern, policy pattern, dependency injection) are related and serve similar ends. Chris |
"Tobias Müller" <troplin@bluewin.ch>: Dec 11 07:52PM > into the local variable `i` inside `foo` and by the time the function > returns, the reference returned by the function is already undefined, > before the assignment is made to the local variable `i` in `main()`. No, nothing is moved here. There is exactly one objects and it lives on the stack of main. Everything else is just references to that. RValue references _don't_ imply moving. They are a useful tool for defining move constructors, but not more. They behave just like normal references, except that they only bind to rvalues. But they are still just references. Tobi |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 11 08:24PM On Fri, 11 Dec 2015 19:52:08 -0000 (UTC) Tobias Müller <troplin@bluewin.ch> wrote: [snip] > defining move constructors, but not more. > They behave just like normal references, except that they only bind to > rvalues. But they are still just references. In the code given: A& foo(A&& a) { return a; } int main() { A aa = foo(A()); } there are two objects not one. First, the temporary create by the call to A(), which lasts until the end of the full expression in which it is situated, and secondly the named object aa which lasts until the end of main() and which is initialized by the temporary. The question is whether the construction of aa is within the full expression within which the temporary is created so that the initialization is valid. As I understand it, it is, so the code is valid. If that is right (and to be honest I would never bother looking it up because I would never write code like this), this also means that the compiler might elide the two objects into one, depending on whether the default constructor and move constructor of A have observable side effects. Chris |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 11 08:31PM On Fri, 11 Dec 2015 20:24:50 +0000 Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote: [snip] > { > A aa = foo(A()); > } [snip] > means that the compiler might elide the two objects into one, > depending on whether the default constructor and move constructor of > A have observable side effects. Or possibly even if they do have observable side effects if RVO on constructing 'aa' is permitted in these circumstances; and I do not know if it is or it isn't (I suspect it isn't, but that is a guess). |
"Tobias Müller" <troplin@bluewin.ch>: Dec 11 08:40PM > write code like this), this also means that the compiler might elide the > two objects into one, depending on whether the default constructor and > move constructor of A have observable side effects. Oops yes that was sloppy. What I really wanted to write is, that _in the context of foo_ there's only one object that lives _outside_ of foo. But in foo itself there are no temporaries and nothing is moved around. Especially there is no local _object_ 'a' as implied by Ayrosa. Whether A() lives long enough for the final assignment or not is a different question. Tobi |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 11 08:48PM On Fri, 11 Dec 2015 20:40:04 -0000 (UTC) > Whether A() lives long enough for the final assignment or not is a > different question. However, in the case posited it is _the_ question! Chris |
"Tobias Müller" <troplin@bluewin.ch>: Dec 11 08:54PM >> Whether A() lives long enough for the final assignment or not is a >> different question. > However, in the case posited it is _the_ question! That was the question of the OP, yes. But I was trying to correct a false statement made by Ayrosa: > exactly the same thing, i.e., the return value of `foo` is a reference to > a local variable, which has already beed destructed, by the time the > assignment is made to the variable `aa` in main(). Tobi |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 11 08:59PM On 11 Dec 2015 20:38:29 GMT > demo( ::std::move( a )); } > &a = 0x01414c > &b = 0x01414c The rvalue reference behaves like a reference, and the lvalue reference behaves like a reference. What else could you possibly have expected? Chris |
Martin Shobe <martin.shobe@yahoo.com>: Dec 11 03:02PM -0600 On 12/11/2015 2:38 PM, Stefan Ram wrote: > An experiment with an implementation showed, however, > that, instead, the rvalue reference behaves like a > lvalue reference, not like an object: Which is good since an rvalue reference is not an object. Martin Shobe |
ram@zedat.fu-berlin.de (Stefan Ram): Dec 11 08:38PM >>int& foo(int&& i){ return i; } >Fundamental types have no move constructors, >so the argument value should be /copied/ into »i« AFAIK. An experiment with an implementation showed, however, that, instead, the rvalue reference behaves like a lvalue reference, not like an object: #include <iostream> #include <ostream> #include <utility> #define PRINT(X) ::std::cout << "&" #X " = " << &X << '\n'; void demo( int && b ) { PRINT(b); } int main() { int a = 8; PRINT(a); demo( ::std::move( a )); } &a = 0x01414c &b = 0x01414c |
Daniel <danielaparker@gmail.com>: Dec 11 11:36AM -0800 On Thursday, December 10, 2015 at 4:56:32 PM UTC-5, Mr Flibble wrote: > 5) Use the memory allocated by std::vector<POD>::reserve() without > constructing elements by bypassing std::vector's modification functions > (e.g. push_back). Regulars advocate this? Seriously? Daniel |
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