提问人:user12655242 提问时间:11/12/2023 最后编辑:Toby Speightuser12655242 更新时间:11/12/2023 访问量:55
将 std::reference_wrapper 转发到 lambda 参数时忽略常量
Constness ignored when forwarding std::reference_wrapper to lambda argument
问:
对于以下简单类:
#include <iostream>
#include <string>
#include <thread>
#include <cstring>
struct Foo_t {
int size;
char *ptr;
Foo_t(int s = 0):size(s),
ptr(size? new char[size]:nullptr) {
std::cout << "\nDefault Ctor...\n";
}
Foo_t(const Foo_t& obj): size(obj.size),
ptr(size? new char[size]:nullptr) {
memmove(ptr, obj.ptr, size*sizeof(char));
std::cout << "Move Ctor... [" << (void*)this << ", ptr " << (void*)ptr << "| from " << (void*)&obj << "]\n";
}
Foo_t(Foo_t&& obj): size(obj.size),
ptr(obj.ptr) { // Move constructor
obj.ptr = nullptr;
std::cout << "Move Ctor... [" << (void*)this << ", ptr " << (void*)ptr << "| from " << (void*)&obj << "]\n";
}
Foo_t(const char* ptr_) : size((ptr_ != nullptr) ? (strlen(ptr_) + 1) : 0),
ptr(size? new char[size]:nullptr) {
strcpy(ptr, ptr_);
std::cout << "Overload Ctor... [" << (void*)this << "| ptr " << (void*)ptr << "]\n";
}
void swap(Foo_t& obj1, Foo_t& obj2) {
std::swap(obj1.size, obj2.size);
std::swap(obj1.ptr, obj2.ptr);
}
Foo_t& operator=(Foo_t obj) {
std::cout << "Generalized assignment to [" << (void*)this << "], from [" << &obj <<"]...\n";
swap(*this, obj);
return *this;
}
~Foo_t() {
delete[] ptr;
std::cout << "Dtor... [" << (void*)this << "| ptr: " << (void*)ptr << "]\n";
}
friend std::ostream& operator<<(std::ostream& os, const Foo_t& ft_);
};
bool operator==(const Foo_t& lhs_, const Foo_t& rhs_) {
return !strcmp(lhs_.ptr, rhs_.ptr);
}
std::ostream& operator<<(std::ostream& os, const Foo_t& ft_) {
os << (ft_.ptr ? std::string(ft_.ptr) : std::string());
return os;
}
为什么以下 lambda 中的恒常性似乎被忽略了?对 fArg.ptr[0] 的两个赋值都不应该导致编译失败吗?
int main() {
std::cout << "\n----- auto threadFuncExample4(threadStorage4); //const Foo_t& arg -------\n";
auto ft4{Foo_t("Foo_t example4")};
auto threadStorage4{std::reference_wrapper<Foo_t>{ft4}};
auto threadFuncExample4 = [](const Foo_t& fArg){
std::cout << "\nthreadFuncExample4 [" << fArg.size << "]\n";
fArg.ptr[0] = 'W'; //This should cause a compilation failure
};
threadFuncExample4(std::forward<Foo_t>(threadStorage4));
std::cout << "threadStorage4 [" << threadStorage4 << "]\n";
std::cout << "\n----- std::thread([](const Foo_t& fArg){}, std::ref(ft11)); -------\n";
Foo_t ft11(Foo_t("Foo_t arg"));
std::thread t11([](const Foo_t& fArg){
std::cout << "\nt11 [" << fArg.size << "]... tid[" << std::this_thread::get_id() << "]\n";
fArg.ptr[0] = 'W'; //This should cause a compilation failure
},
std::ref(ft11));
t11.join();
std::cout << "ft11 [" << ft11 << "]\n";
return 0;
}
编译时:
bash-3.2$ g++ -g -Wall -std=c++2a ThreadArgs.C -o TA.out
bash-3.2$ g++ -v Apple clang version 15.0.0 (clang-1500.0.40.1)
Target: x86_64-apple-darwin23.0.0
(也在 http://coliru.stacked-crooked.com)
它输出如下:
----- auto threadFuncExample4(threadStorage4); //const Foo_t& arg -------
Overload Ctor... [0x7ffe6e435a00| ptr 0x1348030]
threadFuncExample4 [15]
threadStorage4 [Woo_t example4]
----- std::thread([](const Foo_t& fArg){}, std::ref(ft11)); -------
Overload Ctor... [0x7ffe6e435a10| ptr 0x1348050]
t11 [13]... tid[139705825490688]
ft11 [Woo_t arg]
Dtor... [0x7ffe6e435a10| ptr: 0x1348050]
Dtor... [0x7ffe6e435a00| ptr: 0x1348030]
请指教。
PS 以上内容的动机是试图理解 std::thread 构造函数参数是如何存储和构造的。参考:为什么编译器抱怨 std::thread 参数在转换为 rvalues 后必须是可调用的?
如上所述,由于 lambda 参数的恒定性,我预计会出现 2 次编译失败
答: 暂无答案
评论
const
Foo_t
const
ptr
char* const
char const *
char const * const
std::strdup
strndup
std::free