无法在C++中存储指向类的指针

问题描述 投票:0回答:1

我正在编写一个模型套件集合管理器,为此我编写了一个 shell,其中包含一些像这样的变量:

class MonkeyShell {
private:
    bool _exitFlag; // Value that keeps the loop going until we input the command "exit" in terminal.
    std::vector<std::string> _commands; // Vector of commands that we get from the terminal.
    std::map<std::string, std::function<void()>> commandMap; // A map to all of the corresponding command/functions.
    MonkeyManager _manager; // A class that handles file opening, saving, closing etc...
    MonkeyCollection _collection; // The class containing a vector of "MonkeyModels" and the timezone used in the file.
    std::string _level; // what to print on the prompt in the loop.
}

但是现在,我想实现一个新值,当输入命令“edit”时,它会“重定向”到 _collection 中已经存在的 MonkeyModel,这样我就可以处理模型而无需进行复制和复制再次,节省一些资源。

我在学校的第一年都在使用 C 语言,我的反应是在 MonkeyShell 类中添加一个如下所示的变量:

MonkeyModel* _selectedModel

完成后,我编写了一个编辑函数,该函数从 _collection 获取要编辑的模型的编号,看起来像这样:

void MonkeyShell::editCommand() {
    std::string modelNumberString;
    int modelNumber = 0;
    int i = 0;

    std::cout << "Which model do you want to work on ?" << std::endl << _collection << std::endl;
    std::getline(std::cin, modelNumberString);
    modelNumber = std::stoi(modelNumberString) - 1; // When printing the collection, the models are listed with the first index being 1, so we substract one to fit.
    _selectedModel = &_collection.getModels().at(modelNumber); // Here, we should be getting the address of the model we want from the collection and then put it in _selectedModel
}

但这不起作用,它会出现段错误...

所以我这样做是为了检查我的 .getModels 命令是否有效,是的,它只在最后一个 std::cout 时崩溃,前两个命令有效。

void MonkeyShell::debugCommand() {
    MonkeyModel test = _collection.getModels().at(0);
    MonkeyModel* test_p = &test;
    _selectedModel = &_collection.getModels().at(0);

    std::cout << "test of .getModels().at(0) " << test.getName() << std::endl;
    std::cout << "test of &.getModels().at(0) " << test_p->getName() << std::endl;
    std::cout << "Address of _selectedModel: " << _selectedModel << std::endl;
}

所以现在我到了这里,想知道模型向量对于 _collection 来说是私有的这一事实是否会使指针以某种方式破坏自身?

c++ pointers segmentation-fault
1个回答
0
投票

C++(和 C++

std
库)默认使用基于值的语义。
std::vector<X>
是一个。如果您创建它的副本,您还将复制其所有内容。

_selectedModel = &_collection.getModels().at(0);

这里使用的函数

getModels()
返回一个
std::vector
按值。因此创建了向量的临时副本。然后,您对其调用
.at(0)
,给出对该临时副本的第一个元素的引用,然后执行
&
来获取临时副本的第一个元素的地址,将该地址存储在
_selectedModel
中。

声明结束。当 C++ 语句完成时,临时对象通常会被销毁。所以你有一个悬空指针。

 modelNumber = std::stoi(modelNumberString) - 1;
 _selectedModel = &_collection.getModels().at(modelNumber);

这是一个 DRY(不要重复自己)失败的例子。数据

modelNumber
_selectedModel
字段重复相同的信息。

在你的例子中

modelNumber
是一个局部变量,所以你很快就会忘记它。但请考虑记住
modelNumber
而不是
_selectedModel

modelNumber
_selectedModel
的成本很低。指向
std::vector
的指针是危险的,因为
std::vector
管理它们所在的内存 - 看似不相关的操作可能会使它们失效。

MonkeyModel const* getSelectedModel() const {
  if (m_collection.size() >= modelNumber)
    return nullptr;
  return &(m_collection[modelNumber]);
}
MonkeyModel* getSelectedModel() {
  return const_cast<MonkeyModel*>(
    const_cast<MonkeyShell const*>(this)->getSelectedModel()
  );
}

(const-cast 实现也是一种 DRY 尝试)。

现在实施

MonkeyModel& MonkeyCollection::operator[](std::ptrdiff_t i)&
MonkeyModel const& MonkeyCollection::operator[](std::ptrdiff_t i) const&
。确保你不会搞砸并返回对临时对象的引用!

© www.soinside.com 2019 - 2024. All rights reserved.