c++ - 在用户插入数据之前创建结构对象时,Vector 返回乱码

标签 c++ pointers boost vector

我在练习使用指针时偶然发现了一些我不理解的东西。该程序执行以下操作:

  1. 创建一个 vector
  2. 将 vector 的地址传递给函数
  3. 那个函数有一个for循环
  4. 在该 for 循环中,要求用户提供电影名称
  5. 收到电影名称后,将创建一个新的电影对象(来自结构)
  6. 为每部电影创建一个新的 boost 线程,传递用户制作的标题以及新电影对象和 vector 的指针。
  7. 在 boost 线程中,电影对象的“title”变量被赋予用户制作的标题,然后电影被添加到 vector 中
  8. 当所有线程都完成后,“main”函数内的 for 循环会显示 vector 中存储的所有电影标题。

当我交换这两个时出现问题

//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;

当我将“用户输入部分”放在“创建新电影”部分上方时,就像现在一样,我得到了:

good

但是当我交换它们时:

bad

我不明白为什么,因为它们根本不会相互影响。

数据显示如下:

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;
}

最佳答案

获取用户输入和初始化 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 不是很明显 - 但它可能在 main 的末尾。

这种幼稚的方法在指针所有权、内存管理以及潜在的死锁和竞争条件方面打开了一大堆蠕虫。您现在已经进入了多线程编程领域——C++ 编程中最难正确完成的事情之一。上面的幼稚方法将“起作用”(就像防止代码崩溃一样),尽管并非没有缺陷——但是如果您正走在多线程编程的道路上,那么是时候开始研究如何正确地完成它了。这超出了我在这里的小帖子的范围。

关于c++ - 在用户插入数据之前创建结构对象时,Vector 返回乱码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8360506/

相关文章:

c - 如何通过指向结构中的松弛字节来访问另一个变量的数据?

c++ - 如何通过cstdlib系统传递带空格的参数

c++ - boost::bind、boost::function 和 boost::factory 的问题

具有指针值的 C++ 映射

c++ - 与派生类的虚指针混淆

c++ - 如何增加 boost::variant 可以处理的类型数量

c++ - 公开类的 boost::tuple 部分以 boost python

C++:线程同步

c++ - 递归函数导致堆栈溢出

c++ - 写入文件,给出不正确的名称