Подтвердить что ты не робот

Использует ли это использование std:: make_unique для не-уникальных указателей?

Предположим, что у меня есть следующий код в С++:

#include <memory>
#include <iostream>

struct Some {
        Some(int _a) : a(_a) {}
        int a;
};

int main() {
        Some some(5);

        std::unique_ptr<Some> p1 = std::make_unique<Some>(some);
        std::unique_ptr<Some> p2 = std::make_unique<Some>(some);

        std::cout << p1->a << " " << p2->a << std::endl;
        return 0;
}

Как я понимаю, уникальные указатели используются, чтобы гарантировать, что ресурсы не используются. Но в этом случае оба p1 и p2 указывают на один и тот же экземпляр some.

Пожалуйста, сообщите об этом.

4b9b3361

Ответ 1

Они не указывают на один и тот же ресурс, каждый указывает на другую его копию. Вы можете проиллюстрировать это, удалив конструктор копирования, чтобы увидеть ошибку:

#include <memory>
#include <iostream>

struct Some {
        Some(int _a) : a(_a) {}
        Some(Some const&) = delete;
        int a;
};

int main() {
        Some some(5);

        std::unique_ptr<Some> p1 = std::make_unique<Some>(some); //error here
        std::unique_ptr<Some> p2 = std::make_unique<Some>(some);

        std::cout << p1->a << " " << p2->a << std::endl;
        return 0;
}

Ответ 2

std::make_unique создает объекты, вызывающие конструктор с указанными аргументами.

Вы передали Some& в качестве параметра, и здесь был вызван конструктор копирования, а новый объект сконструирован.

Итак, p1 и p2 - 2 абсолютно разных указателя, но построены из одного и того же объекта, используя конструктор копирования

Ответ 3

оба p1 и p2 указывают на один и тот же экземпляр some

Нет, они этого не делают.

#include <memory>
#include <iostream>

struct Some {
        Some(int _a) : a(_a) {}
        int a;
};

int main() {
        Some some(5);

        std::unique_ptr<Some> p1 = std::make_unique<Some>(some);
        std::unique_ptr<Some> p2 = std::make_unique<Some>(some);

        std::cout << p1->a << " " << p2->a << std::endl;
        p1->a = 42;
        std::cout << p1->a << " " << p2->a << std::endl;
        return 0;
}

выход:

5 5
42 5

Ответ 4

Чтобы проверить, указывают ли два указателя на один и тот же экземпляр объекта, вы должны сравнить места, на которые они указывают, вместо переменных-членов объекта:

std::cout << &(*p1) << " " << &(*p2) << std::endl;

Что покажет, что они действительно не указывают на один и тот же экземпляр.

ДОБАВЛЕНИЕ: Как отметил Реми Лебо, с С++ 11 целесообразно использовать std::addressof для этой цели, которая получает фактический адрес объекта, даже если оператор & перегружен:

std::cout << std::addressof(*p1) << " " << std::addressof(*p2) << std::endl;