在用户插入数据之前,在构造struct对象时,Vector返回乱码

nat*_*tli 4 c++ boost pointers vector

我正在练习使用指针,偶然发现了一些我不理解的东西.该程序执行此操作:

  1. 创建一个矢量
  2. 将向量的地址传递给函数
  3. 该函数具有for循环
  4. 在该for循环中,要求用户输入电影名称
  5. 收到电影名称后,将制作一个新的电影对象(来自struct)
  6. 对于每部电影,创建一个新的提升线程,传递用户编写的标题以及新电影对象和矢量的指针.
  7. 在提升线程中,电影对象的"标题"变量被分配用户组成的标题,然后电影被添加到矢量
  8. 当所有线程完成后,"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);
Run Code Online (Sandbox Code Playgroud)

//Create new movie
movies_t amovie;
movies_t * pmovie;
pmovie = &amovie;
Run Code Online (Sandbox Code Playgroud)

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

好

但当我交换它们时:

坏

我不明白为什么,因为它们根本没有相互影响.

数据显示如下:

for(i=0;i<movieVector.size();i++)
{
    cout << movieVector[i].title << endl;
}
Run Code Online (Sandbox Code Playgroud)

这些是相关功能(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;
}
Run Code Online (Sandbox Code Playgroud)

以下是完整的代码,如果重要的话:

#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;
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*ing 5

获取用户输入和初始化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);
Run Code Online (Sandbox Code Playgroud)

您正在将局部变量(amovie)的地址传递给线程.您无法直接控制此线程何时启动,何时尝试访问您已传递的线程,或何时退出.但是你不要在主线程循环中等待工作线程使用本地.一旦循环循环,您传递的变量就会超出范围.当工作线程尝试使用它时,您将调用未定义的行为.这真是太糟了.

可能最简单(也是最天真)的解决方法是动态创建amovie对象:

//Create new movie
movies_t * pmovie = new movies_t;
Run Code Online (Sandbox Code Playgroud)

...然后当你完成使用它,delete它在某个地方.从我最初检查你的代码开始,delete它的位置并不是很明显 - 但它可能在最后main.

这种天真的方法在指针所有权,内存管理以及潜在的死锁和竞争条件方面打开了大量的蠕虫.您现在已经进入了多线程编程领域 - 这是C++编程中最难以正确完成的事情之一.上面的naieve方法将"起作用"(如防止代码崩溃),但不是没有缺陷 - 但是如果你正在走多线程编程的道路,那么就该开始研究如何正确地完成它了.这超出了我在这里的小帖子的范围.