在现代 C++ 中使用原始指针是不好的做法吗?

Is this use of raw pointers in modern C++ bad practice?

我想持有一个没有对象切片的 Base class 实例的向量(这样我也可以毫无问题地存储 Base 的子实例)同时保持多态行为而不通过复制值添加到列表, 而不是引用。

考虑以下源文件:

#include <iostream>
#include <string>
#include <vector>
#include <memory>

class Entity
{
public:
    Entity(){this->edited = false;}
    virtual std::string name() = 0;
    bool edited;
};

class Player: public Entity
{
public:
    Player(): Entity(){}
    std::string name(){return "player";}
};

int main()
{
    std::vector<Entity*> entities;
    Player p;
    entities.push_back(&p);
    entities.at(0)->edited = true;
    Entity* ent = entities.at(0);
    std::cout << "ent = " << ent->name() << ", edited = " << ent->edited << ".\n";
    return 0;
}

我得到以下输出:

ent = player, edited = 1.

如输出所示(通过打印出 "player" 并显示 'edited' 中的变化),由于原始指针,多态行为得以保持,我无需编辑列表成员问题。

澄清我的问题:我可以改用 std::reference_wrapper 来实现完全相同的行为吗?当我尝试使用 reference_wrapper 时,无法实现相同的行为,因为实现此多态行为需要指针?如果 reference_wrapper 不是一个可行的替代方案,虽然我非常清楚我添加到向量中的 Player 实例是一个堆栈变量,但使用 shared_ptr 是否明智?在我的特定示例中,我更喜欢 shared_ptr,因为我希望共享向量成员的所有权。有没有更好的方法来实现这种行为?

那里没有错。唯一可能不好的情况是当您开始分配 Entity 对象并忘记删除它们时。

std::vector<Entity*> entities;
entities.push_back(new Player());

// Somthing that may throw exception

delete entities.at(0)

但这是一个有点不同的问题。

非拥有指针在现代 C++ 中很好。但是如果你的指针是 owning,你最好有充分的理由使用原始指针而不是智能指针。即使在最坏的情况下,您仍然应该能够编写自己的智能指针。你的例子是一个非拥有指针。

使用 std::reference_wrapper<T> 不会给您带来任何好处。我已经包含了您的示例,并进行了修改以使用它。请注意,直接操作向量中的元素会稍微烦人一些。

int main()
{
    std::vector<std::reference_wrapper<Entity>> entities;
    Player p;
    entities.push_back(p);
    entities.front().get().edited = true;
    Entity & ent = entities.front();
    std::cout << "ent = " << ent.name() << ", edited = " << ent.edited << ".\n";
    return 0;
}

原始指针只是一种工具,就像 c++ 提供的许多其他工具一样。当它是正确的工具时,不要害怕使用它。现代 c++ 带来的最重要的变化是它已经取消了拥有原始指针。经验法则是,如果你必须记住 delete 你就做错了。

请注意,std::vector<T>::front() 是获取第一个元素的首选方式,当您知道索引有效时,不鼓励使用 std::vector::at