std::make_unique 的这种使用会导致非唯一指针吗?
Does this use of std::make_unique lead to non-unique pointers?
假设我在 C++ 中有以下代码:
#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
.
请公开情况。
std::make_unique
创建对象,调用指定参数的构造函数。
你传递了Some&
作为参数,这里调用了拷贝构造函数,构造了新的对象。
因此,p1 和 p2 是 2 个完全不同的指针,但是从同一个对象构造,使用复制构造函数
它们不指向 相同的 资源,它们各自指向它的不同 copy。你可以通过删除复制构造函数来说明它看到错误:
#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;
}
要测试两个指针是否指向同一个对象实例,您应该比较它们指向的位置,而不是对象成员变量:
std::cout << &(*p1) << " " << &(*p2) << std::endl;
这将表明它们确实不指向同一个实例。
附录:正如 Remy Lebeau 所指出的,从 C++11 开始,建议使用
std::addressof
函数用于此目的,即使重载 &
运算符,它也能获取对象的实际地址:
std::cout << std::addressof(*p1) << " " << std::addressof(*p2) << std::endl;
both p1
and p2
point to the same instance 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
假设我在 C++ 中有以下代码:
#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
.
请公开情况。
std::make_unique
创建对象,调用指定参数的构造函数。
你传递了Some&
作为参数,这里调用了拷贝构造函数,构造了新的对象。
因此,p1 和 p2 是 2 个完全不同的指针,但是从同一个对象构造,使用复制构造函数
它们不指向 相同的 资源,它们各自指向它的不同 copy。你可以通过删除复制构造函数来说明它看到错误:
#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;
}
要测试两个指针是否指向同一个对象实例,您应该比较它们指向的位置,而不是对象成员变量:
std::cout << &(*p1) << " " << &(*p2) << std::endl;
这将表明它们确实不指向同一个实例。
附录:正如 Remy Lebeau 所指出的,从 C++11 开始,建议使用
std::addressof
函数用于此目的,即使重载 &
运算符,它也能获取对象的实际地址:
std::cout << std::addressof(*p1) << " " << std::addressof(*p2) << std::endl;
both
p1
andp2
point to the same instancesome
#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