我是一名自学成才的c ++程序员(仍处于新手级别)。
我想我已经了解了c ++是如何工作的,但我无法理解这个: 我想用一个由我定义的类的不同元素创建和填充std :: vector:
// other code
while (getline(cfgDataStream, cfgData)) //parsing cycle of the config file
{
std::stringstream ss(cfgData); //creating a stream in order to fill fields
ss >> string1 >> IP1 >> IP2 >> PORT2 >> INDEX;
//they are all strings save the last one, which is a int
if (ss.fail())
{
//bad things happen
}
//FIRST IDEA: Using insert()
CModbusServer MBtemp* = new CModbusServer(this, IP2.c_str(), PORT2, INDEX)
std::vector<CModbusServer*>::iterator iterator = this->m_pServerCollection.begin(); //I get the vector initial position
m_pServerCollection.insert(iterator + (INDEX), MBTemp); // I put the new object in the right index (I don't trust the order in the config file)
//SECOND IDEA: Using push_back()
m_pServerCollection.push_back( new CModbusServer(this, IP2.c_str(), PORT2, INDEX)); //I attach each new object to the end of vector (i trust the order in the config file)
}
基本上我想创建一个CModbusServer对象并将其指针插入一个向量中,这样我在每个向量位置都有n个不同的CModbusServer对象。 这就是我迷失的地方,我尝试了两种插入方式(如代码所示)但没有成功。
CModbusServer包含一个const char * ipAddress字段。如果我尝试访问该字段(即在.Format(_T("%S))
函数中使用它),我会得到随机数据。试着看看为什么我注意到在向量中我没有n个不同的对象,而是用new CModbusServer(this, IP2.c_str(), PORT2, INDEX)
创建的最后一个对象的n个副本。可能这种情况发生的原因是我有一个指针向量,但那些应该是指向不同对象的指针......
我正在使用Visual Studio 2015和MFC来实现基于对话框的应用程序。我有一个AppEngine类,它从其他类调用方法,并有一个CModbusServer元素的向量。 CModbusServer.h如下:
class CModbusServer
{
public:
CModbusServer(void *parentEngine, const char* , unsigned short , int );
~CModbusServer();
const char* ipAddress;
unsigned short port;
int indNode;
modbus_t *MBserver;
bool isConnected;
}
所以,我的问题是:
1)为什么我不能访问ipAddress字段(而不是读取“192.0.2.1”我读取随机字符),而理论上我应该能够使用theApp.CModbusServerVector[properIndex]->ipAddress
读取它?
2)我在填充向量时犯了一个错误,但是我看不出去哪里,最重要的是,为什么它错了。
感谢您的帮助,请原谅我的英语和遗漏。
编辑:
CModbusServer的构造函数代码如下:
CModbusServer::CModbusServer(void *pE, const char* ip, unsigned short nport, int ind)
: parentEngine(pE), //used in order to keep track of the parent dialog
ipAddress(ip),
port(nport),
indNode(ind)
{
this->isConnected = false;
this->m_socket = INVALID_SOCKET;
memset(&m_socketstructhint, 0, sizeof m_socketstructhint);
m_socketstructhint.ai_family = AF_UNSPEC;
m_socketstructhint.ai_socktype = SOCK_STREAM;
m_socketstructhint.ai_protocol = IPPROTO_TCP;
MBserver = modbus_new_tcp(ipAddress, (int)nport);
}
如果我遗漏了任何其他有用的信息,请告诉我。
最初我使用CString
来管理字符串,但后来我遇到了越来越多的问题,最后得到了一个编译和实用的代码const char*
。我设法建立连接并读取所需的modbus寄存器,但后来我陷入了isAddress打印问题。
modbus_new_tc(ip,port)
是一个在libmodbus库中找到的方法,这是一个为C编写的免费软件库,我必须使用它。
编辑2:与回答相关:
所以,如果我是对的,发生的事情是我创建一个临时的指针集,构造函数使用它(我现在已经添加了相关的代码)。但是,不应该是与我作为论点传递的内容无关的构造对象?这些论点不是被复制了吗?对不起,如果问题很愚蠢,但我还在学习。
索引是顺序的,但在配置文件中,也可能是0-1-2-3(每行1个)或0-3-1-2,这就是我的意思“不要相信它们”
由于push_back
方法具有相同的问题,因此问题可能在构造函数中。让我感到困惑的是,通过逐步执行,我可以看到,在while循环的每次迭代中,我得到新的正确数据,但是放在第i个位置的instad被置于第一个i位置(即:原始数据:abc,第一次运行向量= a;第二次运行向量= bb,第三次运行向量= ccc)
我不知道std::unique_ptr<>
,我会查一查。
我试过使用std:string甚至CString,但问题出在libmodbus库下面。
答案 0 :(得分:6)
在c_str
上拨打std::string
会返回&#34;直播&#34;指向存储在std::string
实例中的内部数据的指针。返回的指针指向一个缓冲区,该缓冲区只有在调用它的std::string
保持活动且未修改时才有效。
CExtracalModbusServer
的构造函数只存储传入的指针。只要在输入循环的下一次迭代中重新分配IP2
,该指针就会悬空。 (指向的地址仍然相同,但之前位于该地址的缓冲区已被覆盖,或被释放,或者其他东西。换句话说,指针只是悬空)。
至于插入向量:第一种方式(使用insert
)只有在文件中的索引是顺序的并且从0
开始时才能工作。你需要在向量中插入一个有效的迭代器来插入它,这里有效的意思是指向向量中已有的一个元素,或者指向过去的迭代器(end()
返回的那个)。如果INDEX
等于或大于向量的大小,则m_pServerCollection.insert(iterator + (INDEX), MBTemp);
将尝试插入向量之外(基本上是缓冲区溢出)。随之而来的是Ubnefined行为。
push_back
插入数据的方式应该有效,如果你看到它行为不端,它可能是早期bug(带有悬空指针的那个)的工件,或者有一个单独的问题您尚未展示的代码。
与手头的问题无关,但代码包含手动管理动态内存形式的非常糟糕的做法。不是在向量中存储CModbusServer*
并在所有正确位置使用delete
手动管理内存,而是应该使用std::unique_ptr<CModbusServer>
来处理正确的释放,即使在存在异常。
如果CModbusServer
在您的控制之下,您也应该将其更改为存储std::string
而不是const char*
。除非必须与C风格的API交互,否则永远不要在C ++中使用C风格的字符串,即使在这种情况下,也只限于交互本身。它重复了同样的原则:不要手动管理内存。