如果这很简单,我很抱歉,但我已经玩过C ++超过15年了。
考虑这个简单的例子:
向量包含A
类型的对象。
类B
的对象必须引用驻留在向量中的A
对象。 (编辑以澄清 - 类B
必须有一个引用A
实例的成员)
当天回来你会宣布一个A*
并完成它,但今天如何使用智能指针做到这一点?我不想在向量中存储共享或唯一指针,因为我不希望在堆上分配A对象。它们必须在载体本身中。
答案 0 :(得分:5)
根据您的要求,您有几个选择。
A*
在现代C ++中拥有一个非拥有的原始指针没有任何问题。如果B
需要对A
的可空引用,并且A
可以保证比B
更长,那么原始指针就完全可以了。引用可能需要为空的一个原因是,如果您需要默认构造B
,然后稍后设置引用:
class B {
A* a_ = nullptr;
public:
void setA(A& a) { a_ = &a; }
};
int main() {
std::vector<A> aVec(3);
B b;
b.setA(aVec[1]);
}
A&
如果引用不需要为空。如果引用是在B
的构造函数中设置的,并且永远不会更改,那么您可以使用引用A&
:
class B {
A& a_;
public:
B(A& a) : a_(a) {}
};
int main() {
std::vector<A> aVec (3);
B b(aVec[1]);
}
std::reference_wrapper<A>
使用引用的一个问题是您无法重置引用以指向不同的a
,这意味着您不能拥有setA
成员函数而您无法拥有赋值运算符B::operator=(const B&)
。您可以使用非拥有的原始指针并强制原始指针永远不应为null。但是标准库现在提供了一种称为std::reference_wrapper
的便利,它不能像引用那样为null,但可以像指针一样重新设置:
class B {
std::reference_wrapper<A> a_;
public:
B(A& a) : a_(a) {}
void setA(A& a) { a_ = a; }
};
int main() {
std::vector<A> aVec (3);
B b(aVec[1]);
B otherB(aVec[2]);
b = otherB; // use auto-generated assignment operator
b.setA(aVec[0]);
}
vector
一个常见的情况是vector
的{{1}}正在增长,因此它可能会重新分配并使引用,指针和迭代器无效。在这种情况下,您可以将索引存储到A
中的元素。当vector
增长时,此索引不会失效,您也可以检查索引是否在向量的范围内而不是悬空:
vector
如果您要添加class B {
std::vector<A>& aVec_;
int aIndex_;
public:
B(std::vector<A>& aVec, int aIndex) : aVec_(aVec), aIndex_(aIndex) {}
void useA() {
if (aIndex_ >= 0 && aIndex_ < aVec_.size()) {
auto& a = aVec_[aIndex_];
// use a ...
}
}
};
int main() {
std::vector<A> aVec (3);
B b(aVec, 1);
b.useA();
}
vector
A
,那么这些方法都不会有效,您可能需要重新考虑您的设计。
答案 1 :(得分:3)
智能指针的主要目的是管理生命周期 观察者(即非拥有指针)仍然可以是原始指针。
答案 2 :(得分:1)
显而易见的答案是最简单的,存储对象的索引,而不是地址。