Forum Replies Created
-
AuthorPosts
-
::
Thanks Rainer. I see how this prevents main from trying to get a next value after the execution of the coroutine has reached the end of the body of the coroutine. In this example modified from the initial coroutine: infiniteDataStreamComments.cpp modifed
- When I have two iterations in the coroutine and four iterations in main, I get an error
- When I have three iterations in the coroutine and four iterations in main, I get the last value repeated and no error
Is it undefined behavior to ask for a next value after we have reached the end of the body of the coroutine?
::Actually, maybe it is common for a class parametrized by T to:
- have member functions requiring different concepts on T, and/or
- Have member functions requiring concepts that are more strict than the concept that is required at the class level. From CppReference:
The requirements that are imposed on the elements depend on the actual operations performed on the container. Generally, it is required that element type meets the requirements of Erasable, but many member functions impose stricter requirements. This container (but not its members) can be instantiated with an incomplete element type if the allocator satisfies the allocator completeness requirements.
::Isn’t the same happening in the solution to the exercise with smart pointers where we are returning std::unique_ptr<Interface> in the derived classes, hence not using the covariant return type?
#include <iostream> #include <memory> #include <string> class Interface { public: virtual std::unique_ptr<Interface> clone() const = 0; virtual std::string getName() const = 0; virtual ~Interface() = default; }; class Implementation1 : public Interface { public: std::unique_ptr<Interface> clone() const override { return std::unique_ptr<Interface>( new Implementation1(*this)); } virtual std::string getName() const override { return "Implementation1::getName"; } }; class Implementation2 : public Interface { public: std::unique_ptr<Interface> clone() const override { return std::unique_ptr<Interface>( new Implementation2(*this)); } virtual std::string getName() const override { return "Implementation2::getName"; } }; int main() { Implementation1 my_impl1; std::unique_ptr<Interface> my_clone = my_impl.clone(); //error: //std::unique_ptr<Implementation1> my_clone = my_impl.clone(); }
::I see now that this is discussed in the Modernes post about Null Object:
Runtime Compile time Advantages – Allows it to configure the locking strategy during run time
– Is easier to understand for developers who have an object-oriented background– Has no abstraction penalty
– Has a flat hierarchyDisadvantages – Needs an additional pointer or reference indirection
– It may have a deep derivation hierarchy– It may generate very wordy error messages So a (perhaps too) simplistic summary: compile time for performance and runtime for readability.
::In both examples we are using reference semantics right since we are using Shape* and Shape&? Or do raw pointers model something else?
How would value semantics look like in decorator.cpp? Since we need the indirection via a pointer or a reference to get the polymorphic behavior for instance in the call shape.GetName() I don’t see how we can avoid references when using decorators.
::Thanks Rainer! I appreciate now the differences in the three approaches (ignoring the use of naked new vs. smart pointers) and referring to the diagram from refactoring guru
- factoryMethodClassic.cpp : the creator class hierarchy is replaced by a single function
- factoryMethodUniquePtr.cpp : the creator class hierarchy is blended in with the product hierarchy (i.e. the create methods go directly in the product classes)
- The example in the refactoring Guru: the creator is its own class with concrete classes corresponding to the concrete products
I don’t quite get this comment in the refactoring guru diagram:
“Note, despite its name, product creation is not the primary responsibility of the creator. Usually, the creator class already has some core business logic related to products.”
Is this referring for instance to the render() method in UI example?
::Thanks Rainer! I see also the other instance you describe in your reply to factory-method-as-static-member-of-base-class as another example of when one would use shared_ptr.
::Built-in types:
I think there is no performance difference but the first one has the advantage of disallowing narrowing conversions.
For std::string:
std::string s {“Hello”}; //direct initialization
std::string s = “Hello” //copy initialization
I think there is no difference:
Direct initialization: the constructor taking a const char* is called
Copy initialization: the third bullet point here applies and so the string literal is converted to a prvalue expression of type std::string and then used to direct initialize the object but this last step is optimized away (second bullet point here) and the result of the conversion is constructed directly in the memory allocated for the target object.In general, I don’t know. I realize there are lots of details to keep in mind around initialization whenever I read cppreference pages related to initialization :P
-
AuthorPosts