Correct use of shared_ptr and make_shared in exercise from Stroustrup's PPP book Chapter 12

StackOverflow https://stackoverflow.com/questions/23180205

  •  06-07-2023
  •  | 
  •  

Question

I am working an exercise from Chapter 12 of Bjarne Stroustrup's Programming Principles and Practice Using C++.

The graphics interface library in this chapter, Simple_window.h and Graph.h provides a simple wrapper around FLTK. Source code is available at http://www.stroustrup.com/Programming/Graphics/

To attach a Shape to a Window, users must provide a reference to a Shape object, which must exist for the lifetime of the Window. The relevant member function has the following signature:

void Graph_lib::Window::attach(Shape& s);

Referencing the comments in Difference in make_shared and normal shared_ptr in C++ I would like to make use of std::shared_ptr and std::make_shared to ensure that the allocated Rectangle objects (which derive from Shape) match the lifetime of the Simple_window object (which derives from Window).

First solution:

#include <iostream>
#include <vector>
#include <memory>
#include <stdexcept>
#include "Simple_window.h"
#include "Graph.h"

/*
Exercise 4 from Chapter 12
Programming Principles and Practice using C++, page 434

Draw a checkers board: 8-by-8 alternating white and red squares.
*/

int main()
{
    using namespace std;
    using namespace Graph_lib;
    using Graph_lib::Rectangle;

    try {
        Simple_window win(Point(20,20),400,300,"Exercise 12.4");
        vector<shared_ptr<Shape>> shapes;

        const auto width = 20;
        const auto height = 20;

        for (auto row = 0; row < 8; row++) {
            for (auto col = 0; col < 8; col++) {
                auto x = col * width;
                auto y = row * height;
                shared_ptr<Rectangle> r(new Rectangle(Point(x,y),width,height));
                shapes.push_back(r);
                if (row % 2 == 0) {
                    r->set_fill_color((col % 2 == 0) ? Color::white : Color::red);
                } else {
                    r->set_fill_color((col % 2 == 1) ? Color::white : Color::red);
                }
                win.attach(*r);
            }
        }
        win.wait_for_button();
    }
    catch(exception &e) {
        cerr << "Exception occured: " << e.what() << endl;
        return 1;
    }
    catch(...) {
        cerr << "Unknown exception occured" << endl;
        return 2;
    }
}

To make the use of the smart pointer less explicit I extended Simple_window with a user-defined member function which pushes the smart pointers into the vector before passing the references along to Simple_window::attach(Shape&):

struct Shared_simple_window : Simple_window {
    Shared_simple_window(Point xy, int w, int h, const std::string& title )
        : Simple_window(xy, w, h, title) { }

    void attach(std::shared_ptr<Graph_lib::Shape>&& s)
        { shared_shapes.push_back(s); Simple_window::attach(*s.get()); }

private:
    std::vector<std::shared_ptr<Graph_lib::Shape>> shared_shapes;

};

The code in the try block now becomes

Shared_simple_window win(Point(20,20),400,300,"Exercise 12.4");

const auto width = 20;
const auto height = 20;

for (auto row = 0; row < 8; row++) {
    for (auto col = 0; col < 8; col++) {
        auto x = col * width;
        auto y = row * height;
        shared_ptr<Rectangle> r(new Rectangle(Point(x,y),width,height));
        if (row % 2 == 0) {
            r->set_fill_color((col % 2 == 0) ? Color::white : Color::red);
        } else {
            r->set_fill_color((col % 2 == 1) ? Color::white : Color::red);
        }
        win.attach(r);
    }
}
win.wait_for_button();

This works, but my question is, how can I make use of make_shared in this example rather than new? I tried replacing the shared_ptr declaration with the following

auto r = make_shared<Rectangle>(Rectangle(Point(x,y),width,height));

but I get an error use of deleted function Graph_lib::Rectangle::Rectangle(Graph_lib::Rectangle&&), probably because Rectangle is not designed to be moved. Should I extend Rectangle in order for it to work?

Was it helpful?

Solution

You can try passing the same arguments you would pass to the constructor to make_shared like this:

auto r = make_shared<Rectangle>(Point(x,y),width,height);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top