为什么我的类std :: vector成员总是抛出一个段错误?

时间:2018-05-23 23:13:00

标签: c++

我在SE上无休止地搜索了为什么会发生这种情况的合理解释。我可能忽视了一些非常简单的事情,但是我无法发现它,并且真的很感激这方面的一些帮助。

上周,我实现了一个类来从.ini文件中读取系统调用的输出,然后查找并将所需信息存储到自定义对象中,然后将这些对象存储在Config类的向量中。它是一个Singleton配置类,为我创建的自定义类的每个实例存储unique_ptr。

问题是,当我上周在笔记本电脑上执行此操作时,我有问题读取和写入我的成员向量,并且能够使其完全按照我需要的方式工作。由于拉到我的台式计算机,这个向量,以及我作为我的班级成员使用的任何STL容器,当我尝试对它做任何事情时,都会引发分段错误,甚至是它的大小。

我试图缩短下面的代码,只包含实际使用此向量的部分。我用A替换了我的配置,用T替换了自定义类,无论我在哪里尝试使用我的成员容器,或者我添加到类中的任何其他测试STL容器,我都会遇到段错误。

为了记录,我使用Qt和C ++ 11。

更新:此示例在调试时在c.cpp的第50行和任何尝试调用向量的地方中断。

调试指向stl_vector.h中的这一行

  // [23.2.4.2] capacity
      /**  Returns the number of elements in the %vector.  */
      size_type
      size() const _GLIBCXX_NOEXCEPT
      /*-> this line */ { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }

的main.cpp

#include "c.h"

int main(int argc, char *argv[])
{

    C *c = C::getInstance();

    delete c;

    return 0;
}

t.h - 类存储来自文件的信息

#include <string>

class T
{
public:
    T();

    bool Active();

    std::string getA();
    void setA(std::string);

private:

    std::string a;
};

t.cpp

#include "t.h"

T::T()
{

}

bool T::Active()
{
    if(a == "")
    {
        return false;
    }
    return true;
}

std::string T::getA()
{
    return this->a;
}

void T::setA(std::string newa)
{
    this->a = newa;
}

c.h - 类存储T对象并解析文件以获取信息

#include "t.h"
#include <QDebug>
#include <vector>
#include <algorithm>
#include <iostream>
#include <memory>
#include <sstream>
#include <fstream>

class C
{
public:

    static C* getInstance();

private:
    C();

    static C* instance;
    static bool init;

    std::vector<std::unique_ptr<T>> t_list;
    void readLines(const std::string&);
};

c.cpp

#include "c.h"

bool C::init = false;
C* C::instance = nullptr;

C::C()
{
    system("echo this is a test command > a.ini");
    instance->readLines("a.ini");
}

C* C::getInstance()
{
    if(!init)
    {
        instance = new C;
        init = true;
    }
    return instance;
}

void C::readLines(const std::string &path)
{
    T* new_t;
    std::ifstream file(path.c_str());

    if(!file.is_open())
    {
        qDebug() << "Unable to open " << path.c_str();
    }

    std::ofstream o("test.txt");
    std::string line;
    while(std::getline(file, line))
    {
        // Split string before searching
        std::stringstream ss(line);
        std::string seg;
        std::vector<std::string> split;
        std::string left, right;

        // Search patterns
        size_t find_a = line.find("a");

        size_t del = line.find(':');

        if(find_a != std::string::npos)
        {

            o << "test_Size: " << t_list.size() << std::endl;


            if(new_t->Active())
            {
                T* temp = new_t;
                std::unique_ptr<T> move_t(temp);
                t_list.push_back(std::move(move_t));
            }

            o << "test: " << t_list.size() << std::endl;

            std::string n;

            // Check if previous ahas any null elements

            // Split string to find a
            n = line.substr(line.find("a "));
            n = n.substr(n.find(" ", +2));

            new_t->setA(n);

        }

        else
        {
            continue;
        }
    }

    // Add last a
    T* t = new_t;
    std::unique_ptr<T> move_t(t);
    //t_list.push_back(std::move(move_t));

    o << "a: " << t_list.back().get()->getA() << std::endl;
    o << t_list.size() << std::endl;

    o.close();
    file.close();

}

2 个答案:

答案 0 :(得分:2)

代码更改后

更新:

我现在看到两件事:一件是new_t中的C::readlines永远不会被初始化,所以当函数稍后调用new_t->Active()时,这可能会中断。但是,我认为您遇到的主要问题是C::C(),其中包含

instance->readLines("a.ini");

在执行的这一点上,C::instance尚未初始化 - 您只是构建稍后将分配给它的对象。因此,this调用中的readlines无效,任何访问对象成员的尝试都将导致UB。只需调用

即可解决后一个问题
readLines("a.ini");

在这种情况下,当前构造的对象(稍后将instance)用于this。我不知道你想要为第一个发生什么,所以我只能说:如果你想要一个vector<unique_ptr<T>>,你将不得不创建T类型的对象{ {1}}或(可以说是优选的)new T()并将它们放在那里。

我还要说这是在C ++中实现单例的一种相当丑陋的方式。我的意思是,单身人士从来都不是很漂亮,但如果你要用C ++做,那么通常的做法就像是C++ Singleton design pattern的接受答案。

旧回答:

问题(如果它是唯一的,我无法验证,因为你没有提供MCVE)在行

std::make_unique<T>()

您将指向本地对象的指针传递给T move_t = new_T; std::unique_ptr<Adapter> ptr_t(&move_t); // <-- particularly this one m_ts.push_back(std::move(ptr_t)); ,但std::unique_ptr的全部目的是处理用std::unique_ptr分配的对象以避免内存泄漏。一旦留下围绕此声明的范围,您传入其中的指针不仅无效,即使new尝试unique_ptr对象“{1}}的情况并非如此。在生命周期结束时不在堆上。这两个问题都会导致不确定的行为。

对我而言,您似乎真的想使用delete代替std::vector<T>,但这是一个设计问题,您必须自己回答。

答案 1 :(得分:0)

在这里回答我自己的问题。我试图从包含它的对象的构造函数中调用成员变量,因此我尝试访问的向量尚未实例化,并且不存在于内存中。这就是导致Segmentation错误发生的原因,我正在尝试访问尚未分配的内存,因此任何对我的C类的任何成员执行的调用都会导致此问题。

我通过向该类添加一个公共函数来修复此问题,然后该类调用私有readLines()函数。我从该对象中调用该公共函数,该对象将获得它的所有权,并且因为这在实例化之后发生,所以可以访问内存并且问题消失。