C++11 移动承诺导致的分段错误

C++11 移动承诺导致的分段错误,c++11,stdthread,std-future,C++11,Stdthread,Std Future,我传递了一个承诺作为对线程的引用。之后,promise通过std::move被移动到一个向量中。这会在执行软件时导致分段错误 我想在移动承诺后,线程中的引用永远不会更新?我怎样才能将承诺传递给线程,以便以后可以移动它?请参阅下面的代码示例 #include <iostream> #include <thread> #include <vector> #include <future> class Test { publi

我传递了一个承诺作为对线程的引用。之后,promise通过std::move被移动到一个向量中。这会在执行软件时导致分段错误

我想在移动承诺后,线程中的引用永远不会更新?我怎样才能将承诺传递给线程,以便以后可以移动它?请参阅下面的代码示例

#include <iostream>
#include <thread>
#include <vector>
#include <future>


class Test {        
    public:
    std::thread t;
    std::promise<int> p;
    Test(std::thread&& rt, std::promise<int>&& rp) : t(std::move(rt)), p(std::move(rp)) {}
};

int main()
{
    std::vector<Test> tests;

    {
        auto p = std::promise<int>();
        std::thread t ([&p]{
            std::cout << 1;
            p.set_value(1);
        });
        tests.push_back(Test(std::move(t), std::move(p)));
    }  

    for(Test& mytest : tests)
    {
        mytest.t.join();
    }

}

我对你的问题没有答案。至少,我还没有。然而,似乎还没有其他答案出现,我发现你的问题很有趣,所以让我们试试这个:

#include <iostream>
#include <thread>
#include <vector>
#include <future>
#include <memory>

class Test {        
    public:
    std::thread t;
    std::unique_ptr<std::promise<int>> pp;
    Test(std::thread&& rt, std::unique_ptr<std::promise<int>>&& rpp)
      : t(std::move(rt)), pp(std::move(rpp)) {}
};

int main()
{
    std::vector<Test> tests;

    {
        auto pp = std::make_unique<std::promise<int>>();
        std::thread t ([&pp]{
            std::cout << 1;
            pp->set_value(1);
        });
        tests.push_back(Test(std::move(t), std::move(pp)));
    }  

    for(Test& mytest : tests)
    {
        mytest.t.join();
    }
}
你看到我在那里做了什么吗?我通过一个智能指针间接获得了承诺的所有权。我们知道,智能指针可以优雅地进行破坏,因此该代码不会移动承诺本身,而只移动指向承诺的指针。然而,代码仍然存在错误

那么,我们是否确定承诺实际上是导致SEG故障的原因


也许这个承诺确实导致了这个错误,但现在至少我们有了另一种方法来解决这个问题,除非你已经尝试过这个方法。

我对你的问题没有答案。至少,我还没有。然而,似乎还没有其他答案出现,我发现你的问题很有趣,所以让我们试试这个:

#include <iostream>
#include <thread>
#include <vector>
#include <future>
#include <memory>

class Test {        
    public:
    std::thread t;
    std::unique_ptr<std::promise<int>> pp;
    Test(std::thread&& rt, std::unique_ptr<std::promise<int>>&& rpp)
      : t(std::move(rt)), pp(std::move(rpp)) {}
};

int main()
{
    std::vector<Test> tests;

    {
        auto pp = std::make_unique<std::promise<int>>();
        std::thread t ([&pp]{
            std::cout << 1;
            pp->set_value(1);
        });
        tests.push_back(Test(std::move(t), std::move(pp)));
    }  

    for(Test& mytest : tests)
    {
        mytest.t.join();
    }
}
你看到我在那里做了什么吗?我通过一个智能指针间接获得了承诺的所有权。我们知道,智能指针可以优雅地进行破坏,因此该代码不会移动承诺本身,而只移动指向承诺的指针。然而,代码仍然存在错误

那么,我们是否确定承诺实际上是导致SEG故障的原因

可能是promise确实导致了segfault,但现在至少我们有了另一种解决问题的方法,除非您已经尝试过这个方法。

lambda持有引用的promise p被移出并超出范围。你需要一个额外的间接层次,这样承诺就永远不会移动

auto pp = std::make_unique<std::promise<int>>();
std::thread t ([p = pp.get()] { // <--- p is a promise<int>*
    std::cout << 1;
    p->set_value(1);
});
这样,承诺永远不会移动,你只需移动指针。lambda获取一个指向承诺的常规非所有者指针

查看它。

lambda持有引用的promise p被移出并超出范围。你需要一个额外的间接层次,这样承诺就永远不会移动

auto pp = std::make_unique<std::promise<int>>();
std::thread t ([p = pp.get()] { // <--- p is a promise<int>*
    std::cout << 1;
    p->set_value(1);
});
这样,承诺永远不会移动,你只需移动指针。lambda获取一个指向承诺的常规非所有者指针


查看它。

已确认。我的机器上也有故障,Debian 9、GCC 6.3、Libc6/Pthread 2.4。这很奇怪。我同意你的看法。这个移动应该是好的。线程t的lambda持有对p的引用,它超出了范围,lambda无法知道它移动到了哪里。即使是这样,将其存储在向量中也会导致它再次移动。你可以选择不改变承诺,用另一种间接方式,比如指针。@kmdreko不像我,我相信你可能有正确的答案。我想试试你的建议,但不应该窃取你的信誉。请随意发布您自己的答案,复制和修改我的答案,或其他任何东西。我会投赞成票的。不要在任何地方引用这个承诺。总是把它移到应该完成的地方。在本例中,主线程中唯一可以保留的是关联的未来,在将承诺移动到工作线程中之前,您应该获取它。不要使用[&]来声明可能离开作用域的lambda,这是危险的。在这种情况下,仅按值绑定。或者,如果您不能,比如在本例中,因为std::promise无法复制,请在匿名函数上声明一个r值参数,并通过std::thread.confirm的变量构造函数转发它。我的机器上也有故障,Debian 9、GCC 6.3、Libc6/Pthread 2.4。这很奇怪。我同意你的看法。这个移动应该是好的。线程t的lambda持有对p的引用,它超出了范围,lambda无法知道它移动到了哪里。即使是这样,将其存储在向量中也会导致它再次移动。你可以选择不改变承诺,用另一种间接方式,比如指针。@kmdreko不像我,我相信你可能有正确的答案。我想试试你的建议,但不应该窃取你的信誉。请随意发布您自己的答案,复制和修改我的答案,或其他任何东西。我会投赞成票的。不要在任何地方引用这个承诺。总是把它移到应该完成的地方。在本例中,主线程中唯一可以保留的是关联的未来,在将承诺移动到工作线程中之前,您应该获取它。不要使用[&]来声明可能离开作用域的lambda,这是危险的。在这种情况下,仅按值绑定。或者,如果您不能,就像在本例中,因为std::promise无法复制,请在匿名函数上声明一个r值参数,并通过std::thread的可变构造函数转发它。如果您愿意,只要没有更好的答案出现,就编译并运行代码,考虑
请稍等一下,然后告诉我你的结论。我很想听听。是的,是对空指针的取消引用导致了代码的错误。这里是对它的一个现场测试:这并不完全正确,因为lambda仍然持有对pp的引用,如果您愿意,只要没有更好的答案出现,编译并运行代码,考虑一下,然后告诉我您的结论。我很想听听。是的,是对空指针的取消引用导致了代码的错误。这里有一个现场测试:这并不完全正确,因为lambda仍然引用pp,这超出了澄清的范围,你的是对我的代码的编辑还是对OP的编辑?大部分是你的,这就是为什么我添加源链接来澄清,你的是对我的代码的编辑还是对OP的编辑?大部分是你的,这就是我添加源链接的原因