unique_ptr和多态性



我有一些代码目前使用原始指针,我想更改为智能指针。这有助于以各种方式清理代码。无论如何,我有返回对象的工厂方法,调用方有责任管理它们。所有权不是共享的,所以我认为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());

现在,到发布的原因。我想知道这是否是解决我遇到的问题的正常方法?让Pushunique_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拥有一个对象,因为ipush中的局部参数都将拥有该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);
}

相关内容

  • 没有找到相关文章

最新更新