在用户插入数据之前创建结构对象时,Vector 返回乱码
Posted
技术标签:
【中文标题】在用户插入数据之前创建结构对象时,Vector 返回乱码【英文标题】:Vector returns gibberish when struct object is made before user inserts data 【发布时间】:2011-12-02 17:55:22 【问题描述】:我正在练习使用指针,但偶然发现了一些我不明白的东西。程序这样做:
-
创建矢量
将向量的地址传递给函数
那个函数有一个for循环
在该 for 循环中,要求用户输入电影名称
收到电影名称后,将创建一个新的电影对象(来自结构)
为每部电影创建一个新的 boost 线程,传递用户编造的标题以及新电影对象和向量的指针。
在 boost 线程中,电影对象的“title”变量被赋予用户编造的标题,然后电影被添加到向量中
当所有线程都完成后,“main”函数内的 for 循环会显示存储在向量中的所有电影标题。
当我交换这两个时出现问题
//Get info about new movie from user
string movieTitle;
int movieYear; //Not used at the moment
cout << "Enter title for movie " << (i+1) << endl;
getline(cin,movieTitle);
和
//Create new movie
movies_t amovie;
movies_t * pmovie;
pmovie = &amovie;
当我将“用户输入部分”放在“创建新电影”部分上方时,就像现在一样,我得到了:
但是当我交换它们时:
我不明白为什么,因为它们根本不会相互影响。
数据显示如下:
for(i=0;i<movieVector.size();i++)
cout << movieVector[i].title << endl;
这些是相关函数(main 和 newThreads)
void newThreads(vector<movies_t> *movieVectorPointer)
boost::thread_group group; //Start thread group
int i;
for(i=0; i<2; i++) //Make X amount of threads (2 in this case)
//Get info about new movie from user
string movieTitle;
int movieYear; //Not used at the moment
cout << "Enter title for movie " << (i+1) << endl;
getline(cin,movieTitle);
//Create new movie
movies_t amovie;
movies_t * pmovie;
pmovie = &amovie;
//Let user know we are now starting on this thread
cout << "Doing thread " << i << endl;
//Start new thread
newThreadStruct startNewThread(movieTitle,movieYear,pmovie,movieVectorPointer);
group.create_thread(startNewThread);
group.join_all(); //Wait for all threads in group to finish
int main()
cout << "Hello world!" << endl; //I am born.
vector<movies_t> movieVector; //Create vector to store movies in
newThreads(&movieVector); //Start making new threads. Pass movieVector's address so it can be used within threads.
/* The below code will not be executed until all threads are done */
cout << "Amount of movies " << movieVector.size() << endl; //Let user know how many movies we made
//Show all movies we made
int i;
for(i=0;i<movieVector.size();i++)
cout << movieVector[i].title << endl;
cout << "Bye world!" << endl; //This life has passed.
return 0;
这是完整的代码,以防万一:
#include <iostream>
#include <boost/thread.hpp>
using namespace std;
//A movie will hold a title and a year. Only title is used in this code.
struct movies_t
string title;
int year;
;
//This function is where the data is added to our new movie,a fter which our finished movie will be added to the vector. It is called from within the "newThreadStruct" operator.
int doMovieWork(string movieTitle,int movieYear,movies_t *moviePointer,vector<movies_t> *movieVector)
moviePointer->title = movieTitle; //Add title to new movie
movieVector->push_back(*moviePointer); //Add movie to vector
return 0;
;
//This struct will be used to create new Boost threads. It accepts various arguments.
struct newThreadStruct
newThreadStruct(string movieTitle,int movieYear,movies_t *moviePointer,vector<movies_t> *movieVector) : movieTitle(movieTitle),movieYear(movieYear),moviePointer(moviePointer),movieVector(movieVector)
void operator()()
doMovieWork(movieTitle,movieYear,moviePointer,movieVector);
string movieTitle;
int movieYear;
movies_t *moviePointer;
vector<movies_t> *movieVector;
;
void newThreads(vector<movies_t> *movieVectorPointer)
boost::thread_group group; //Start thread group
int i;
for(i=0; i<2; i++) //Make X amount of threads (2 in this case)
//Get info about new movie from user
string movieTitle;
int movieYear; //Not used at the moment
cout << "Enter title for movie " << (i+1) << endl;
getline(cin,movieTitle);
//Create new movie
movies_t amovie;
movies_t * pmovie;
pmovie = &amovie;
//Let user know we are now starting on this thread
cout << "Doing thread " << i << endl;
//Start new thread
newThreadStruct startNewThread(movieTitle,movieYear,pmovie,movieVectorPointer);
group.create_thread(startNewThread);
group.join_all(); //Wait for all threads in group to finish
int main()
cout << "Hello world!" << endl; //I am born.
vector<movies_t> movieVector; //Create vector to store movies in
newThreads(&movieVector); //Start making new threads. Pass movieVector's address so it can be used within threads.
/* The below code will not be executed until all threads are done */
cout << "Amount of movies " << movieVector.size() << endl; //Let user know how many movies we made
//Show all movies we made
int i;
for(i=0;i<movieVector.size();i++)
cout << movieVector[i].title << endl;
cout << "Bye world!" << endl; //This life has passed.
return 0;
【问题讨论】:
你知道你有几个编译器警告吗? @JohnDibling 我相信比较有符号和无符号的东西。不,我直到现在才注意到这一点。是否相关? 当您的线程启动时,您的本地对象不会超出范围? 与这个具体问题无关,但很糟糕。您应该在最高警告级别上干净地编译所有代码。不要忽视警告——它们正试图帮助你。 【参考方案1】:获取用户输入和初始化movies_t
对象的顺序是一个红鲱鱼。实际问题在这里:
//Create new movie
movies_t amovie;
movies_t * pmovie;
pmovie = &amovie;
/* ... */
//Start new thread
newThreadStruct startNewThread(movieTitle,movieYear,pmovie,movieVectorPointer);
group.create_thread(startNewThread);
您正在将局部变量 (amovie
) 的地址传递给线程。您无法直接控制该线程何时启动、何时尝试访问您传递给它的指针或何时退出。但是您不会在主线程循环中等待工作线程使用本地。一旦循环循环,您传递的变量就会超出范围。当工作线程尝试使用它时,您会调用未定义的行为。这很糟糕。
解决这个问题的最简单(也是最天真的)方法可能是动态创建amovie
对象:
//Create new movie
movies_t * pmovie = new movies_t;
...然后当你用完它时,delete
它在某个地方。从我对您的代码的初步检查来看,delete
的位置并不是很明显——但它可能在main
的末尾。
这种幼稚的方法在指针所有权、内存管理以及潜在的死锁和竞争条件方面打开了一大堆蠕虫。您现在已经进入了多线程编程领域——在 C++ 编程中最难正确完成的事情之一。上面的幼稚方法将“有效”(如防止您的代码崩溃),尽管并非没有缺陷 - 但如果您正在走多线程编程的道路,那么是时候开始研究如何正确地做到这一点了。这远远超出了我在这里的小帖子的范围。
【讨论】:
所以如果我理解正确的话,等待用户输入实际上只是暂停了循环的其余部分,允许我在此之前创建一个循环的线程使用该变量?我的印象是,每个循环都会创建一个全新的变量(如内存中的一个新位置)。但据我了解,我需要使用new
来实现这一点?我在哪里可以学习如何“正确地做这件事”?既然你说这是一种幼稚的开始方式。
循环的每次迭代都会生成一个新变量。问题在于,当循环迭代或退出时,该变量也会被破坏。【参考方案2】:
错误在以下几行:
movies_t amovie;
movies_t * pmovie;
pmovie = &amovie;
在这里您创建一个局部变量amovie
,并将指针分配给该局部变量。当局部变量超出范围时,即循环结束或循环结束时,则变量占用的内存不再有效。所以指针pmovie
指向未使用的内存。
你必须使用new
分配指针:
movies_t *pmovie = new movie_t;
【讨论】:
这当然会导致内存泄漏。请看我的帖子。以上是关于在用户插入数据之前创建结构对象时,Vector 返回乱码的主要内容,如果未能解决你的问题,请参考以下文章
R语言head函数和tail函数获取dataframe列表list向量vector的头部和尾部数据:tail提取数据对象的尾部数据head提取数据对象的头部数据默认6条数据自定义设置返回条数
设计一种结构,在该结构中有如下三个功能:insert(key):将某个key加入到该结构,做到不重复加入。delete(key):将原本在结构中的某个key移除。 getRandom():等概率随机返