Forum Replies Created
- AuthorPosts
- ::
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 😛
::The clang-tidy rule modernize-pass-by-value suggests to replace the use of const references constructor parameters that are copied into class fields with a pass by value that is then moved.
::Thank you all for your posts! Very interesting.
I work on the timing model of FPGAs. An FPGA is a device that has an undefined function at the time of manufacture, it is programmed on the field. A large component of the product is the software that is used to program the device and verify that it will function as expected. Part of that verification is making sure that data can be reliably transferred from register to register in the FPGA and between registers on the FPGA and other devices on the board, that’s where the timing model for the device comes in.
I am responsible for part of the data that is consumed by the timing model and I am currently restructuring how we store, verify and query package parasitics and I am adding new functionality to support new packaging methodologies.
::Thanks Driton! Yes this is one instance where I thought this could happen.
The part that I was missing is that this doesn’t result in a deadlock because as you say condVar1 releases the mutex, goes to sleep and waits for the notification. I agree one thread could acquire the lock at most twice in a row since the second time around the wait call fails and the thread is blocked until the other thread returns the ball.
It could happen multiple times I think, just each time at most twice in a row, for instance if for some reason the call to lock in the last row of the table below (vertical axis is time) gets delayed and t1 has a chance to acquire the lock again before t2 gets a chance to do so. Ultimately the ping pong functionality remains the same with the two threads taking turns in changing the value of the variable.
t2(set_false) t1(set_true) lock wait success set variable to true notify lock wait fail unlock lock wait success set variable to false notify wait success lock set variable to true lock - AuthorPosts