Home > Back-end >  C shared_ptr and mutex
C shared_ptr and mutex

Time:02-12

I'm new to C and I have to following scenario:

main.cpp

#include "Foo.h"
#include "Bar.h"

int main() {
    Bar bar{};
    auto bar_ptr = std::make_shared<Bar>(bar);

    for (int i = 0; i < 10; i  ) {
        Foo foo{bar_ptr};
    }

    return 0;
}

I want 10 Instances of Class Foo to share 1 Instance of Class Bar. Each Instance of Class Foo will run in a separate Thread. I want the shared Instance of Class Bar only to be accessed by one Instance of Foo at a time. That's why I wanted to add a std::mutex to Foo. This seems to conflict with std::mutex not being copyable/moveable. What is the correct way to use a mutex with a shared_ptr?

Foo.h

#include <memory>
#include <utility>
#include "Bar.h"

class Foo {
    std::shared_ptr<Bar> bar_ptr;

public:
    explicit Foo(std::shared_ptr<Bar> bar_ptr){
        this->bar_ptr = std::move(bar_ptr);
    }
};

Bar.h

#include <mutex>

class Bar {
    std::mutex mutex{};

};

CodePudding user response:

std::mutex is a move-only type, so you can't copy it.

In your main function you are creating a Bar, and then trying to create a std::shared_ptr by copying that instance of Bar.

Instead, just use std::make_shared<Bar>() to create a shared_ptr to a bar with the default constructor.

#include "Foo.h"
#include "Bar.h"

int main() {
    auto bar_ptr = std::make_shared<Bar>();

    for (int i = 0; i < 10; i  ) {
        Foo foo{bar_ptr};
    }

    return 0;
}

To clarify, the arguments passed to make_shared are forwarded to the constructor of the class. If you pass a Bar& it will try to use the copy constructor.

If you pass nothing it will use the default constructor.

If Bars constructor takes arguments in your real use-case, pass the arguments to make_shared.

#include <memory>
#include <utility>
#include <mutex>

class Bar {
    public:
    Bar(int i) : value(i) {}
    private:
    std::mutex mutex{};
    int value;
};

class Foo {
    std::shared_ptr<Bar> bar_ptr;

public:
    // Use the initializer list when possible
    // Otherwise we first default-construct then assign
    explicit Foo(std::shared_ptr<Bar> ptr) : bar_ptr(std::move(ptr)) {}
};

int main() {
    auto bar_ptr = std::make_shared<Bar>(5);

    for (int i = 0; i < 10; i  ) {
        Foo foo{bar_ptr};
    }

    return 0;
}
  • Related