Использует ли это использование 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
.
Пожалуйста, сообщите об этом.
Ответы
Ответ 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;