Forum Replies Created

Viewing 15 posts - 136 through 150 (of 349 total)
  • Author
    Posts
  • in reply to: Solution of covariantReturnType exercise #575239
    RainerRainer
    Keymaster
        Up
        0
        Down
        ::

        Your observation is right. The implementation of clone based on a std::unique_ptr is no covariant return type. It only simulates a covariant return type using an upcast. Smart pointers (std::unique_ptr and std::shared_ptr) do not support the covariant return type. This is a C++ language limitation.

        in reply to: swap and ADL #571287
        RainerRainer
        Keymaster
            Up
            0
            Down
            ::

            Thanks to the hidden friend idiom, the compiler finds the  swap implementation defined in Foo.  If Bar has no optimized swap, std::swap kicks in.

            Here is the following example on goldbolt: https://godbolt.org/z/WTKdT4rPK

            #include <algorithm>
            #include <iostream>
            
            
            struct Foo {
                friend void swap(Foo&, Foo&){
                    std::cout << "hidden friend\n";
                }
            };
            
            struct Bar{};
            
            template <typename T>
            void swapMe(T& a, T& b) {
                std::cout << "callSwap\n";
                using std::swap;
                swap(a, b);
            }
            
            int main() {
            
                Foo f, f2;
                swapMe(f, f2);
            
                std::cout << "\n";
                
                Bar b, b2;
                swapMe(b, b2);
            
            }
            
            in reply to: Safe variant example of modifyVector #571286
            RainerRainer
            Keymaster
                Up
                0
                Down
                ::

                I’m don’t know in detail how the strong exception guarantee is provided but here are a few thoughts.
                First, the move constructor of T must be noexcept.

                If an allocation is required due to the push_back call, the follwing steps happen:

                1. Allocate a buffer
                2. Construct the value in the new buffer
                3. Move the values from the old buffer to the new one

                This means, that the original vector is only modified in step 3. Step 1 and 2 must have rollback semantics.

                in reply to: Line 31 of nullObject.Cpp contains an error? #566799
                RainerRainer
                Keymaster
                    Up
                    0
                    Down
                    ::

                    Right. It should call nullObjectMutex.unlock(). Due to the fact that the nullObjectMutex.lock() has not effect, I probably didn’t recognized the error.

                    in reply to: Safe variant example of modifyVector #564437
                    RainerRainer
                    Keymaster
                        Up
                        0
                        Down
                        ::

                        Of course, this example is hypothetical. Suppose, modifyVector throws and catches its exception. Now, you have no idea in which state tmp is. In this case, you don’t care because myVec was not modified.

                        A try except block does not give you rollback semantics. Assume, modifyVector throws an exception after some side effect such as std::cout. Even when you catch the exception in the main function, the std::cout call cannot be undone.

                        RainerRainer
                        Keymaster
                            Up
                            0
                            Down
                            ::

                            You cannot annotate a function with the “strong exception guarantee”. Therefore, the compiler does not know if the function provides the “strong exception guarantee”.  You can only assign noexcept to a function. The expression “strong exception guarantee” is a semantic categorization, but noexcept a syntactic constraint (keyword).

                            in reply to: Composite vs. visitor #555333
                            RainerRainer
                            Keymaster
                                Up
                                1
                                Down
                                ::

                                Exactly.

                                • Composite Pattern: Manage a tree like-structure in a uniform way. In your case, you wanted to apply do_action on all nodes.
                                • Visitor Pattern: Separate algorithms from the objects they operate on. The key idea is that the objects are stable, but the algorithms may change.
                                in reply to: passing by smart pointer vs reference #555332
                                RainerRainer
                                Keymaster
                                    Up
                                    0
                                    Down
                                    ::

                                    Passing by non-const reference means that this a so-called in-out parameter.

                                    void addSomethingToVector(std::vector<int>& myVec) {
                                        myVec.push_back(5);
                                    }
                                    
                                    in reply to: passing by smart pointer vs reference #554381
                                    RainerRainer
                                    Keymaster
                                        Up
                                        0
                                        Down
                                        ::

                                        Semantically, there is a big difference between passing by const reference or passing by std::shared_ptr.

                                        • Const reference: you model borrowing
                                        • std::shared_ptr: you model ownership

                                        With modern C++, you don’t pass ownership with pointers or references.

                                        in reply to: Testing a Method which runs in a thread #553169
                                        RainerRainer
                                        Keymaster
                                            Up
                                            0
                                            Down
                                            ::
                                            1. My question is if the function run can be executed by more than one thread simultaneously. If so, there is a race condition.
                                            2. If run is executed single threaded I have another question. You assume in your function that the following calls are executed in one atomic step. This should be provided because you act on a local msg that provides you transactional semantics.

                                            auto msg = input_.waitDequeueNotification();
                                            if (msg)output_.enqueueNotification(std::move(msg));     
                                            
                                            in reply to: Testing a Method which runs in a thread #553167
                                            RainerRainer
                                            Keymaster
                                                Up
                                                0
                                                Down
                                                ::

                                                First of all, is the run member function atomic?

                                                void run() {
                                                        while (is_running_) {
                                                            calculate();
                                                            auto msg = input_.waitDequeueNotification();
                                                            if (msg) {
                                                                output_.enqueueNotification(std::move(msg));
                                                            }
                                                        }
                                                    }
                                                

                                                If not, you have a race condition. It is likely the msg may be consumed more than once. This is pretty similar to my example “Breaking of invariants” here: https://www.modernescpp.com/index.php/malicious-race-conditions.

                                                in reply to: Testing a Method which runs in a thread #552938
                                                RainerRainer
                                                Keymaster
                                                    Up
                                                    0
                                                    Down
                                                    ::

                                                    I need more background information:

                                                    1. What do you want to test?
                                                    2. Is run an event-loop that calculates something and wait for input and output events?
                                                    3. Can see input and output events happen concurrently?
                                                    in reply to: Upgrading to smart pointers #552924
                                                    RainerRainer
                                                    Keymaster
                                                        Up
                                                        0
                                                        Down
                                                        ::

                                                        Exactly. You have a std::unique_ptr<Sofa> which could own a Sofa. I completed your example and added a default constructor to Sofa. You see that no Sofa is created (https://godbolt.org/z/KG9x9f6Wb):

                                                        #include <iostream>
                                                        #include <memory>
                                                        
                                                        class Sofa {
                                                         public:
                                                            Sofa() {
                                                                std::cout << "Sofa created";
                                                            }
                                                        };
                                                        
                                                        class House {
                                                            public:
                                                                House(): sofa2(nullptr) {}
                                                            private:
                                                                std::unique_ptr<Sofa> sofa;
                                                                Sofa* sofa2;
                                                        };
                                                        
                                                        int main() {
                                                            House h;
                                                        }
                                                        

                                                        In this case, it would be fine if the constructor of Sofa is private.

                                                        RainerRainer
                                                        Keymaster
                                                            Up
                                                            0
                                                            Down
                                                            ::

                                                            Thanks. Fixed. For some reason, this was a link requiring an administrative account.

                                                            in reply to: Pointers stored in composite #550632
                                                            RainerRainer
                                                            Keymaster
                                                                Up
                                                                1
                                                                Down
                                                                ::

                                                                Excellent point. You should prefer smart pointers to raw pointers. This rule still applies for design patterns. I start in my design pattern mentoring classically. Consequentially, my implementations are pointer based. In upcoming weeks, I modernize these patterns and introduce idioms.

                                                                By the way, most of the time I use a pointer to a local and have, therefore, no memory issues.

                                                                Here is the composite based on std::shared_ptr.

                                                                #include <iostream>
                                                                #include <memory>
                                                                #include <string>
                                                                #include <vector>
                                                                
                                                                class Graphic {
                                                                 public:
                                                                    virtual void print() const = 0;
                                                                    virtual ~Graphic() {} 
                                                                };
                                                                
                                                                class GraphicComposite : public Graphic {
                                                                    std::vector<std::shared_ptr<const Graphic>> children;
                                                                    const std::string& name;
                                                                 public:
                                                                    explicit GraphicComposite(const std::string& n): name(n){}
                                                                    void print() const override {
                                                                        std::cout << name << " ";
                                                                        for (auto c: children) c->print();
                                                                    }
                                                                
                                                                    void add(std::shared_ptr<const Graphic> component) {
                                                                        children.push_back(component);
                                                                    }
                                                                
                                                                    void remove(std::shared_ptr<const Graphic> component) {
                                                                        std::erase(children, component);
                                                                    }
                                                                };
                                                                
                                                                class Ellipse: public Graphic {
                                                                 private:
                                                                    const std::string& name;
                                                                 public:
                                                                    explicit Ellipse(const std::string& n): name (n) {}
                                                                    void print() const override {
                                                                        std::cout << name << " ";
                                                                    }
                                                                };
                                                                
                                                                int main(){
                                                                
                                                                    std::cout << '\n';
                                                                
                                                                    const std::string el1 = "ellipse1";
                                                                    const std::string el2 = "ellipse2";
                                                                    const std::string el3 = "ellipse3";
                                                                    const std::string el4 = "ellipse4";
                                                                
                                                                    auto ellipse1 = std::make_shared<Ellipse>(el1);
                                                                    auto ellipse2 = std::make_shared<Ellipse>(el2);
                                                                    auto ellipse3 = std::make_shared<Ellipse>(el3);
                                                                    auto ellipse4 = std::make_shared<Ellipse>(el4);
                                                                
                                                                    const std::string graph1 = "graphic1";
                                                                    const std::string graph2 = "graphic2";
                                                                    const std::string graph3 = "graphic3";
                                                                
                                                                    auto graphic1 = std::make_shared<GraphicComposite>(graph1);
                                                                    auto graphic2 = std::make_shared<GraphicComposite>(graph2);
                                                                
                                                                    auto graphic = std::make_shared<GraphicComposite>(graph3);
                                                                
                                                                    graphic1->add(ellipse1);
                                                                    graphic1->add(ellipse2);
                                                                    graphic1->add(ellipse3);
                                                                
                                                                    graphic2->add(ellipse4);
                                                                
                                                                    graphic->add(graphic1);
                                                                    graphic->add(graphic2);
                                                                
                                                                    graphic1->print();
                                                                    std::cout << '\n';
                                                                
                                                                    graphic2->print();
                                                                    std::cout << '\n';
                                                                
                                                                    graphic->print();
                                                                
                                                                    std::cout << '\n';
                                                                
                                                                    graphic->remove(graphic1);
                                                                
                                                                    graphic->print();
                                                                
                                                                    std::cout << "\n\n";
                                                                
                                                                }
                                                                

                                                                Now, I can optimize the implementation and share nodes. This is a very nice use case of std::shared_ptr.

                                                                In the following implementation (https://godbolt.org/z/73zroqfKx), I have only one ellipse and I remove it from graphic2. Observe the use count of ellipse.

                                                                #include <iostream>
                                                                #include <memory>
                                                                #include <string>
                                                                #include <vector>
                                                                
                                                                class Graphic {
                                                                 public:
                                                                    virtual void print() const = 0;
                                                                    virtual ~Graphic() {} 
                                                                };
                                                                
                                                                class GraphicComposite : public Graphic {
                                                                    std::vector<std::shared_ptr<const Graphic>> children;
                                                                    const std::string& name;
                                                                 public:
                                                                    explicit GraphicComposite(const std::string& n): name(n){}
                                                                    void print() const override {
                                                                        std::cout << name << " ";
                                                                        for (auto c: children) c->print();
                                                                    }
                                                                
                                                                    void add(std::shared_ptr<const Graphic> component) {
                                                                        children.push_back(component);
                                                                    }
                                                                
                                                                    void remove(std::shared_ptr<const Graphic> component) {
                                                                        std::erase(children, component);
                                                                    }
                                                                };
                                                                
                                                                class Ellipse: public Graphic {
                                                                 private:
                                                                    const std::string& name;
                                                                 public:
                                                                    explicit Ellipse(const std::string& n): name (n) {}
                                                                    void print() const override {
                                                                        std::cout << name << " ";
                                                                    }
                                                                };
                                                                
                                                                int main(){
                                                                
                                                                    std::cout << '\n';
                                                                
                                                                    const std::string el = "ellipse";
                                                                
                                                                    auto ellipse = std::make_shared<Ellipse>(el);
                                                                
                                                                    const std::string graph1 = "graphic1";
                                                                    const std::string graph2 = "graphic2";
                                                                    const std::string graph3 = "graphic3";
                                                                
                                                                    auto graphic1 = std::make_shared<GraphicComposite>(graph1);
                                                                    auto graphic2 = std::make_shared<GraphicComposite>(graph2);
                                                                
                                                                    auto graphic = std::make_shared<GraphicComposite>(graph3);
                                                                
                                                                    graphic1->add(ellipse);
                                                                    graphic1->add(ellipse);
                                                                    graphic1->add(ellipse);
                                                                
                                                                    graphic2->add(ellipse);
                                                                
                                                                    graphic->add(graphic1);
                                                                    graphic->add(graphic1);
                                                                
                                                                    graphic1->print();
                                                                    std::cout << '\n';
                                                                
                                                                    graphic2->print();
                                                                    std::cout << '\n';
                                                                
                                                                    graphic->print();
                                                                
                                                                    std::cout << '\n';
                                                                
                                                                    std::cout << "ellipse.use_count(): " << ellipse.use_count() << '\n';
                                                                
                                                                    graphic2->remove(ellipse);
                                                                
                                                                    graphic->print();
                                                                
                                                                    std::cout << '\n';
                                                                
                                                                    std::cout << "ellipse.use_count(): " << ellipse.use_count() << '\n';
                                                                
                                                                    std::cout << "\n\n";
                                                                
                                                                }
                                                                
                                                              Viewing 15 posts - 136 through 150 (of 349 total)