指向矢量元素的持久指针代替"this"
persistent pointer to vector element in place of 'this'
我需要指向std::vector
元素的持久指针。直接的this
不行,如图所示:
#include <functional>
#include <vector>
#include <iostream>
class A {
public:
A() = delete;
A(int i)
: my_i(i)
, whoAmI([this]()->void{ std::cout<<"I am class A with i="<<my_i<<std::endl; })
{}
A(const A&) = delete;
A(A&&) = default;
int my_i;
std::function<void()> whoAmI;
};
int main()
{
std::vector<A> vec;
std::cout << "Initialization:" << std::endl;
for (int i=0; i<3; ++i) {
vec.push_back(A(i));
vec.back().whoAmI();
}
std::cout << "Retrieval:" << std::endl;
for (int i=0; i<3; ++i)
vec.at(i).whoAmI();
}
产生
Initialization:
I am class A with i=0
I am class A with i=1
I am class A with i=2
Retrieval:
I am class A with i=2
I am class A with i=2
I am class A with i=2
而我需要
Retrieval:
I am class A with i=0
I am class A with i=1
I am class A with i=2
当然,在这个例子中,人们可以很容易地绕过它。在现实生活中,持久指针应传递给Qt::connect
。
也许可以尝试按如下值捕获索引:
#include <functional>
#include <vector>
#include <iostream>
class A {
public:
A() = delete;
A(int i, std::vector<A> &vec)
: whoAmI([i, &vec]()->void{
std::cout<<"I am class A with i="<< i << ". Calling whoAmI(): " << std::endl;
vec[i];
})
{}
A(const A&) = delete;
A(A&&) = default;
std::function<void()> whoAmI;
};
int main()
{
std::vector<A> vec;
std::cout << "Initialization:" << std::endl;
for (int i=0; i<3; ++i) {
vec.push_back(A(i, vec));
vec.back().whoAmI();
}
std::cout << "Retrieval:" << std::endl;
for (int i=0; i<3; ++i)
vec.at(i).whoAmI();
}
您在lambda的inizalization站点上绑定了它,因此在任何情况下都无法实现对象的移动或复制。
一个可能的解决方案是添加一个间接级别:
#include <functional>
#include <vector>
#include <iostream>
class A;
class fuction_wrapper
{
public:
A* ref;
std::function<void(A*)> lambda;
void operator()() const { lambda(ref); }
};
class A {
public:
A() = delete;
A(int i)
: my_i(i)
, whoAmI({this, [] (A* a) { std::cout<<"I am class A with i="<< a->my_i << std::endl; }})
{}
A(const A&) = delete;
A(A&& a)
{
my_i = std::move(a.my_i);
whoAmI = { this, std::move(a.whoAmI.lambda) };
}
int my_i;
fuction_wrapper whoAmI;
};
int main()
{
std::vector<A> vec;
std::cout << "Initialization:" << std::endl;
for (int i=0; i<3; ++i) {
vec.push_back(A(i));
vec.back().whoAmI();
}
std::cout << "Retrieval:" << std::endl;
for (int i=0; i<3; ++i)
vec.at(i).whoAmI();
}
可能不是最能养眼的解决方案,但它确实有效。
您需要在move构造函数中重新定义lambda,以便它在移动后获得更新的this
,因为您推入的临时A(i)
已经不存在了。
A(A&& a)
{
this->my_i = a.my_i;
this->whoAmI = [this]()->void { std::cout << "I am class A with i=" << this->my_i << std::endl; };
};
https://ideone.com/s5ZyS5
Initialization:
I am class A with i=0
I am class A with i=1
I am class A with i=2
Retrieval:
I am class A with i=0
I am class A with i=1
I am class A with i=2
如果不涉及移动构造函数A(A&&)
,就无法设置std::vector<A>
的元素。移动后,旧的this
正在悬挂。让我们称之为移动这个问题。
此外,矢量元素地址可能会随着矢量的增长而变化。这个问题可以通过保留足够的向量大小来解决,也可以通过将向量元素封装在唯一指针中来解决。然而,这些措施都没有解决这个问题,因此这是更根本的问题。
移动这个问题有几个解决方案:
-
不使用
this
,而是捕获拥有的向量和向量索引(请参阅@bartop的解决方案( -
更新move构造函数中的lambda表达式(请参阅@Jack和@KillzoneKid的解决方案(
-
插入一个单独的
init
函数:,而不是在常规构造函数中初始化lambda表达式,并在move构造函数中更新它
class A {
...
A(int i) : my_i(i) {}
/* A(A&&) = default; */
void init();
...
};
void A::init() {
whoAmI = [this]()->void{ std::cout<<"I am class A with i="<<my_i<<std::endl; };
}
int main()
{
std::vector<A> vec;
std::cout << "Initialization:" << std::endl;
for (int i=0; i<3; ++i) {
vec.push_back(A(i));
vec.back().init();
vec.back().whoAmI();
}
...
}
然而,在对我的QObject::connect
应用程序进行了几天的实验之后,我得出的结论是,通过将相关逻辑移动到父类(在这里显示的最小示例中:移动到main
(来避免整个问题要好得多。
- 为什么使用 "this" 指针调用派生成员函数?
- 关于C++中具有多重继承"this"指针的说明
- Doees the 'this' 指针参与虚函数的多态行为
- 指针'this+1' C++中指的是什么?
- 为什么使用指向函数的指针调用虚函数时不需要指针"this"?
- Lambda 函数捕获错误的指针"this"
- 调用类的方法时,类的指针"this"变为 null C++
- 指针'this'可以是共享指针吗?
- 如何在C++中为指针'this'赋值
- C++:指针"this"没用吗?
- 指针"this"有什么问题?
- 将指针'this'传递为 LPARAM
- 错误 C2663:指针'this'重载没有合法转换
- C++ : 了解指针"this"
- 更改对象的指针'this'以指向不同的对象
- C++编译器是为所有成员方法生成指针"this"还是仅为引用成员的方法生成指针?
- 使用指针和不使用指针"this"有区别吗?
- 将enable_shared_from_这个基于类的指针(this)存储在itelf中
- 创建指向对象的指针"this"
- 如何在类中取消初始化指针"this"?