Use of std::vector::emplace_back
Use of std::vector::emplace_back
我有一些std::线程的类扭曲器。下面是构造函数:
template <typename Function, typename... Args>
InterruptibleThread(Function&& fun, Args&&... args)
{
_thread = std::thread([](std::atomic_bool * f, Function&& function, Args&&... arguments)
{
_flag_ref = f;
(function)(std::forward<Args>(arguments)...);
},
&_flag,
std::forward<Function>(fun)
, std::forward<Args>(args)...
);
}
然后我这样使用它(示例):InterruptibleThread(&SourceImageList::StartFrameProcessingStatic, this, std::ref(it))
编译器成功构建此代码。但是现在我想为这样的对象创建一个向量:
std::vector<InterruptibleThread> grp;
我想在堆栈上分配它所以我要做的是:
grp.emplace_back(&SourceImageList::StartFrameProcessingStatic, this, std::ref(it));
我得到这个错误:
C2064 term does not evaluate to a function taking 0 arguments
以下是编译器验证的选项:
1) grp.push_back(new InterruptibleThread(&SourceImageList::StartFrameProcessingStatic, this, std::ref(it)));
2) grp.push_back(InterruptibleThread(&SourceImageList::StartFrameProcessingStatic, this, std::ref(it)));
但是第一个是在堆上分配一个对象,所以我需要手动释放它,第二个是对象的副本。
我可以在这里使用emplace_back
(编译器是MSVC 2015更新3)?
好的,我根据答案做了一些修复。下面是这个类的最终版本:
#pragma once
#include <exception>
#include <atomic>
#include <thread>
#include <future>
#include <windows.h>
// Synopsis
class InterruptThreadException;
class InterruptibleThread;
// Interrupt exception
class InterruptThreadException : public virtual std::exception {
public:
virtual char const* what() const override { return "interrupt"; }
}; // class InterruptThreadException
// Interruptible thread
class InterruptibleThread {
public:
static void InterruptionPoint() noexcept(false) {
if (!InterruptibleThread::_flag_ref) { return; }
if (!InterruptibleThread::_flag_ref->load()) { return; }
throw InterruptThreadException();
} // check_for_interrupt
template <typename Function>
InterruptibleThread(Function&& fun) :
_thread([this, fun = std::move(std::forward<Function>(fun))]
{
_flag_ref = _flag.get();
fun();
})
{}
InterruptibleThread(InterruptibleThread&&) = default;
InterruptibleThread(const InterruptibleThread&) = delete;
bool Interrupting() const { return _flag->load(); }
void Interrupt() { _flag->store(true); }
void Join()
{
_thread.join();
}
bool TimedJoin(int msec)
{
return (std::async([=]() {Join(); }).wait_for(std::chrono::milliseconds(msec)) != std::future_status::timeout);
}
bool Joinable()
{
return _thread.joinable();
}
void Terminate()
{
TerminateThread(_thread.native_handle(), -1);
}
~InterruptibleThread()
{
if (_flag.get() != nullptr)
{
*_flag = false;
Interrupt();
}
if (_thread.joinable())
_thread.join()
}
private:
static thread_local std::atomic_bool* _flag_ref;
std::unique_ptr<std::atomic_bool> _flag = std::make_unique<std::atomic_bool>();
std::thread _thread;
};
使用示例:
std::vector<InterruptibleThread> grp;
for (auto it : _sourceImages)
grp.emplace_back([this, it] {
it->StartFrameProcessing();
it->SetImageDelay(const_cast<EngineConfig*>(GetConfig())->ImageDelay);
});
你可以现代化你的代码,并传递一个lambda到InterruptibleThread
,而不是传递一个函数和它的参数(即绑定风格)。
#include <atomic>
#include <iostream>
#include <thread>
#include <vector>
struct InterruptibleThread
{
std::thread _thread;
template <typename Function>
InterruptibleThread(Function&& fun)
: _thread(std::forward<Function>(fun))
{
}
};
struct Test
{
std::vector<InterruptibleThread> grp;
void test(int x) {
grp.emplace_back([this, x]{ t1(x); }); // <==== HERE
}
void t1(int x) {
std::cout << x << "n";
}
};
int main()
{
Test t;
t.test(5);
t.grp[0]._thread.join();
}
我的猜测是,直接的问题是向量类试图实例化类的移动构造函数,这恰好与模板签名相匹配,但随后无法用Function = InterruptibleThread, Args = {}
编译主体。您需要通过显式默认move构造函数来提供重写。
除此之外,还有几点:
- 如前所述,构造函数不应该使用指针到成员函数和
- 它不在代码示例中,但看起来_flag是
atomic_bool
类型的成员变量。这将阻止默认的move构造函数被实例化。
std::reference_wrapper
参数。(它不能在gcc下工作,我不知道它如何在MSVC中工作。)这是我在gcc下编译的修改版本:
#include <thread>
#include <mutex>
#include <atomic>
#include <vector>
#include <utility>
thread_local std::atomic_bool* _flag_ref;
class InterruptibleThread {
private:
std::thread _thread;
// Need unique_ptr instead of a directly contained atomic_bool
// to make the object MoveConstructible.
std::unique_ptr<std::atomic_bool> _flag;
public:
template <typename Function, typename... Args>
explicit InterruptibleThread(Function&& fun, Args&&... args)
{
_flag = std::make_unique<std::atomic_bool>();
// Use std::bind to take care of all the details of
// calling pointer-to-member-function or pointer-to-member-variable,
// unwrapping std::reference_wrapper arguments, etc.
auto bound_fun = std::bind(std::forward<Function>(fun), std::forward<Args>(args)...);
_thread = std::thread([this, bound_fun = std::move(bound_fun)]
{
_flag_ref = _flag.get();
bound_fun();
}
);
}
InterruptibleThread(InterruptibleThread&&) = default;
InterruptibleThread(const InterruptibleThread&) = delete;
};
class Foo {
public:
void func(int& n);
};
void test_func() {
std::vector<InterruptibleThread> v;
Foo f;
int n = 5;
v.emplace_back(&Foo::func, &f, std::ref(n));
}
相关文章:
- TMap::Emplace() 在应用现有密钥时会覆盖吗?
- 推导 std::vector::back() 的返回类型
- 为什么 C++ std::unordered_map 从 emplace/ 找到返回一个迭代器?
- vector.back() 和 vector[vector.size() - 1] 之间的区别?
- 将 std::map::emplace 与返回 shared_ptr 的函数一起使用是否正确?
- vector.push_back(vector.back()+1) 是未定义的行为吗?
- 不为 emplace() 定义构造函数的解决方法
- 如何提取由 unordered_map::emplace 重新调整的货币对的值?
- 如何最好地将 emplace 与 std::map 一起使用
- 线路抑制状态错误 C4703 可能未初始化的局部指针变量"back"已使用
- std::vector using back(), pop_back(), push_back(), 得到'double free or corruption'错误
- std::vector::emplace() 真的在面对抛出移动构造函数/赋值运算符时提供了强大的异常保证吗?
- std::map::emplace无法解决,但插入右值有效 - 为什么?
- vector.back()和vector.end()有什么区别
- 为什么 std::map emplace 需要在 gcc 上有一个复制构造函数
- 为什么unordered_map的 emplace piecewise_construct参数需要默认构造函数?
- std::元组到元组的映射和使用 emplace
- 列表大小为 1,但 front() 和 back() 不相等
- 如何使用 emplace 添加到C++中的地图
- C++ map emplace