【问题标题】:A vector member is reset and unaccessible向量成员已重置且无法访问
【发布时间】:2018-07-30 15:48:32
【问题描述】:

我有两个项目,一个基本客户端和一个动态库。 以下是客户端中发生的情况:

int main()
{
    Scrutinizer scru;
    scru.Scrutinize();
    return 0;
}

在 DLL 中,Scrutinizer 类是这样的(__declspec(dllexport) 并且为了清晰而省略了这样的类)

标题

class ProcessesGenerator;

    class Scrutinizer
    {
    public:
    Scrutinizer();
    ~Scrutinizer();
    ProcessesGenerator *ProcGenerator
    void Scrutinize();
};

ProcessesGenerator 的前向声明对我来说是“强制性的”,以避免某种循环引用。

.cpp 文件中的构造函数

我是这样初始化的:

Scrutinizer::Scrutinizer()
{
    ProcGenerator = &ProcessesGenerator();
}

更多关于这个ProcessesGenerator类:

标题

class ProcessesGenerator
{

public:
    ProcessesGenerator();
    ~ProcessesGenerator();
    WinFinder winFinder;
    std::vector<std::string> fooCollec;

    void GenerateProcesses();
};

ProcessesGenerator.cpp

构造函数:

ProcessesGenerator::ProcessesGenerator()
{
    //winFinder = WinFinder();//problem will be the same with or without this line
    fooCollec = std::vector<std::string>{"one", "two", "three"};
}

构造函数中的断点表明向量已使用所选值初始化。

有问题的功能:

void ProcessesGenerator::GenerateProcesses() {
    std::string foo = "bar";
    fooCollec = std::vector<std::string>{};//read access violation
    fooCollec.push_back(foo);//read access violation
    winFinder.SomeVector= std::vector<std::string>{};//read access violation
}

在那里,我可以看到向量的大小被重置为 0。任何重新初始化它或推送元素的尝试都会导致读取访问冲突。与其WinFinder 成员的 vecotr 成员相同。我猜这个缺陷很明显,但我真的不明白,

谢谢!

【问题讨论】:

  • 你用的是什么编译器? ProcGenerator = &amp;ProcessesGenerator(); 不应该编译。
  • 我在 Windows 10 下的 Visual Studio 2017 上,并使用“构建”功能或单击“本地 Windows 调试器”进行编译
  • @NathanOliver 这是众所周知的讨厌的 MS 功能 - 温度到左值的隐式转换
  • @Slava 这只是犯罪。这和他们将临时对象绑定到非 const 引用一样糟糕。

标签: c++ pointers vector forward-declaration


【解决方案1】:

你的问题是

Scrutinizer::Scrutinizer()
{
    ProcGenerator = &ProcessesGenerator();
}

您正在做的是获取临时对象的地址。该对象将被销毁,并且该行的末尾将留下一个不指向有效对象的指针。

修复它的旧方法是使用

Scrutinizer::Scrutinizer()
{
    ProcGenerator = new ProcessesGenerator();
}

但是现在你必须实现复制构造函数、复制赋值操作符和析构函数。既然你有一个现代编译器,你可以做的是把ProcGenerator 变成std:unique_ptr&lt;ProcessesGenerator&gt; 然后Scrutinizer() 变成

Scrutinizer::Scrutinizer() : ProcGenerator(make_unique<ProcessesGenerator>()) {}

我还想补充一点,&amp;ProcessesGenerator(); 甚至不应该编译。不幸的是,MSVS 有一个非标准的扩展,允许它编译。您可以打开 /Za 编译器选项(强制 ANSI 兼容性),然后您应该会收到类似的错误

错误 C2102:“&”需要左值

【讨论】:

  • 非常感谢您抽出时间来帮助和教导!它适用于一个最小的项目,但我的实际项目向我展示了让我首先使用前向声明的奇怪错误。几个小时后我无法修复它,所以我没有让它成为类的成员并在需要时创建一个新实例。我想从 C# 到 C++ 的转变不会发生得这么快……无论如何还是谢谢
【解决方案2】:

ProcGenerator = &amp;ProcessesGenerator(); 行创建一个临时的ProcessesGenerator,获取其地址,然后将其放入您的ProcGenerator 指针中。然后临时销毁,留下垃圾。

您可能希望在堆上分配它ProcGenerator = new ProcessesGenerator;,但即使在这种情况下,我还是强烈建议使用unique_ptr 而不是原始指针。

【讨论】:

    猜你喜欢
    • 2012-12-21
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 2016-05-03
    • 2015-08-06
    • 2018-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多