我在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();
}
答案 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()
函数。我从该对象中调用该公共函数,该对象将获得它的所有权,并且因为这在实例化之后发生,所以可以访问内存并且问题消失。