我有一些代码目前使用原始指针,我想更改为智能指针。这有助于以各种方式清理代码。无论如何,我有返回对象的工厂方法,调用方有责任管理它们。所有权不是共享的,所以我认为unique_ptr
是合适的。我返回的对象通常都派生自单个基类,Object
.
例如
class Object { ... };
class Number : public Object { ... };
class String : public Object { ... };
std::unique_ptr<Number> State::NewNumber(double value)
{
return std::unique_ptr<Number>(new Number(this, value));
}
std::unique_ptr<String> State::NewString(const char* value)
{
return std::unique_ptr<String>(new String(this, value));
}
返回的对象通常需要传递给另一个函数,该函数对类型为Object
(基类)的对象进行操作。没有任何智能指针,代码是这样的。
void Push(const Object* object) { ... } // push simply pushes the value contained by object onto a stack, which makes a copy of the value
Number* number = NewNumber(5);
Push(number);
将此代码转换为使用unique_ptrs
时,我遇到了多态性问题。最初,我决定简单地更改Push
的定义以使用unique_ptrs
,但是在尝试使用派生类型时,这会产生编译错误。我可以分配对象作为基本类型,例如
std::unique_ptr<Object> number = NewNumber(5);
并将其传递给Push
- 这当然有效。但是,我经常需要在派生类型上调用方法。最后,我决定Push
操作指向unique_ptr
存储的对象的指针。
void Push(const Object* object) { ... }
std::unique_ptr<Object> number = NewNumber(5);
Push(number.get());
现在,到发布的原因。我想知道这是否是解决我遇到的问题的正常方法?让Push
对unique_ptr
进行操作比对对象本身进行操作更好吗? 如果是这样,如何解决多态性问题?我认为简单地铸造 ptrs 是行不通的。需要从智能指针获取基础指针是否常见?
谢谢,抱歉,如果问题不清楚(请告诉我)。
编辑:我认为我的推送功能有点模棱两可。它创建基础值的副本,实际上不会修改或存储输入对象。
最初我决定简单地更改推送的定义 unique_ptrs也是,但这会在尝试使用时产生编译错误 派生类型。
您可能没有正确处理唯一性。
void push(std::unique_ptr<int>);
int main() {
std::unique_ptr<int> i;
push(i); // Illegal: tries to copy i.
}
如果这样编译,它将微不足道地破坏unique_ptr
的不变量,即只有一个unique_ptr
拥有一个对象,因为i
和push
中的局部参数都将拥有该int
,所以它是非法的。unique_ptr
只是移动,它是不可复制的。它与派生到基本转换无关,unique_ptr
完全正确处理。
如果push
拥有该对象,则使用std::move
将其移动到该对象。如果没有,请使用原始指针或引用,因为这是您用于非拥有别名的指针或引用。
好吧,如果你的函数对(指向的)对象本身进行操作并且不需要它的地址,那么也不拥有任何所有权,而且,正如我猜的,总是需要一个有效的对象(传递nullptr
时失败),为什么它们要接受指针?
正确执行并使它们引用:
void Push(const Object& object) { ... }
然后,原始指针和智能指针的调用代码看起来完全相同:
auto number = NewNumber(5);
Push(*number);
编辑:但当然,无论是使用引用还是指针,如果它没有获得传递对象的所有权,请不要Push
采取std::unique_ptr
(这将使它从传递的指针中窃取所有权)。或者一般来说,当指向的对象不被拥有时,不要使用拥有指针,std::shared_ptr
在这方面没有任何不同,如果Push
没有所有权,则与Push
参数的std::unique_ptr
一样糟糕。
如果Push
不采用 owenrship,它可能应该采用引用而不是指针。而且很可能是const
的。所以你会有
Push(*number);
现在,这显然仅在 Push 不会将指针保留在其返回之后的任何位置时才有效。如果是这样,我怀疑你应该先尝试重新考虑所有权。
下面是使用唯一指针的多态性示例:
vector<unique_ptr<ICreature>> creatures;
creatures.emplace_back(new Human);
creatures.emplace_back(new Fish);
unique_ptr<vector<string>> pLog(new vector<string>());
for each (auto& creature in creatures)
{
auto state = creature->Move(*pLog);
}