简体   繁体   English

这是在现代C ++糟糕实践中使用原始指针吗?

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

I want to hold a vector of Base class instances without object slicing (Such that I can also store instances of a child of Base without issue) while maintaining polymorphic behaviour without adding to the list by copying values, but rather by reference. 我想要保存一个没有对象切片的Base类实例的向量(这样我也可以存储没有问题的Base的子实例),同时保持多态行为,而不是通过复制值而是通过引用添加到列表中。

Consider the following source file: 请考虑以下源文件:

#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;
}

I obtain the following output: 我获得以下输出:

ent = player, edited = 1.

As the output shows (via printing out "player" and showing the change in 'edited'), polymorphic behaviour is maintained due to the raw pointer and I am able to edit members of the list without issue. 当输出显示(通过打印出“播放器”并显示“已编辑”中的更改)时,由于原始指针而保持多态行为,并且我能够毫无问题地编辑列表成员。

To clarify what I'm asking: Could I instead use an std::reference_wrapper to achieve the exact same behaviour? 澄清我在问什么:我可以使用std :: reference_wrapper来实现完全相同的行为吗? When I tried using a reference_wrapper, the same behaviour could not be achieved as pointers are required to achieve this polymorphic behaviour? 当我尝试使用reference_wrapper时,由于需要指针来实现这种多态行为,所以无法实现相同的行为? If reference_wrappers are not a viable alternative, although I know full-well that the instance of Player that I added to the vector is a stack-variable, would it be sensible to instead use a shared_ptr? 如果reference_wrappers不是一个可行的选择,虽然我完全知道我添加到向量中的Player实例是一个堆栈变量,但是使用shared_ptr是否明智? In my particular example I would favour a shared_ptr due to the fact that I want shared ownership of the members of the vector. 在我的特定示例中,我倾向于使用shared_ptr,因为我想要向量的成员共享所有权。 Are there any better ways of achieving this behaviour? 有没有更好的方法来实现这种行为?

Non-owning pointers is fine in modern c++. 在现代c ++中,非拥有指针很好。 But if your pointer is owning , you better have a very good reason for using a raw pointer instead of a smart pointer. 但是如果你的指针是拥有的 ,你最好有一个很好的理由使用原始指针而不是智能指针。 Even in the worst case, you should still be able to write your own smart pointer. 即使在最坏的情况下,您仍然可以编写自己的智能指针。 Your example is a non-owning pointer. 您的示例是非拥有指针。

Using std::reference_wrapper<T> doesn't gain you anything here. 使用std::reference_wrapper<T>在这里没有任何帮助。 I've included your example, modified to use it. 我已经包含了你的例子,修改后使用它。 Notice that it's slightly more annoying to directly manipulate elements in your vector. 请注意,直接操作向量中的元素会稍微烦一些。

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;
}

A raw pointer is just a tool, like many others offered by c++. 原始指针只是一种工具,就像c ++提供的许多其他工具一样。 Don't be afraid to use it when it's the right tool . 当它是正确的工具时,不要害怕使用它。 The most significant change brought on by modern c++ is that it has done away with owning raw pointers. 现代c ++带来的最重大变化是它已经取消了拥有原始指针。 The rule of thumb is if you have to remember to delete you are doing it wrong. 经验法则是,如果你必须记得delete你做错了。

Note that std::vector<T>::front() is the preferred way of obtaining the first element and the use of std::vector::at is discouraged when you know your index is valid. 请注意, std::vector<T>::front()是获取第一个元素的首选方法,当您知道索引有效时std::vector::at不建议使用std::vector::at

There is nothing wrong there. 那里没有错。 The only case where it could be bad is when you will start allocate Entity objects and will forget to delete them. 它可能是坏的唯一情况是你将开始分配实体对象并忘记删除它们。

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

// Somthing that may throw exception

delete entities.at(0)

But this is a little bit different problem. 但这是一个有点不同的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM