persistent pointer to vector element in place of 'this'

Multi tool use
Multi tool use
The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


persistent pointer to vector element in place of 'this'



I need persistent pointers to elements of std::vector. Straightforward this won't do, as demonstrated here:


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();
}



Which yields


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



whereas I need


Retrieval:
I am class A with i=0
I am class A with i=1
I am class A with i=2



Of course, in this example one could easily work around. In real life, the persistent pointer shall be passed to Qt::connect.


Qt::connect





I'm not sure I understand the problem, but I suspect std::enable_shared_from_this may solve it.
– François Andrieux
49 mins ago


std::enable_shared_from_this





@FrançoisAndrieux Sounds like a pretty heavyweight solution. But on second thought, maybe the best.
– Passer By
46 mins ago







Surprised this didn't fault, as the capture of this and saving it in the std::function is invalided when the vector has to reallocate.
– Richard Critten
41 mins ago




this


std::function





@Richard Critten It does not even fault if the loop limit is set to a million instead of 3.
– Joachim W
37 mins ago





There is really no solution, as vector elements are moved all the time and can even be deallocated when vector expands. The closest thing to a solution is having a vector of pointers. Another possibility is to use list.
– Arkadiy
35 mins ago




list




2 Answers
2



You are binding this at inizialization site of your lambda, so this is not going to work in in any circumstance the object is moved or copied indeed.



A possible solution could be to add a level of indirection:


#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();
}



Probably not the most eye-candy solution available but it works.



Maybe try capturing indexes by value like this:


#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();
}





Won't help when it comes to Qt::connect ... except if I access some global variable to access vec in order to access vec[i].
– Joachim W
31 mins ago


Qt::connect


vec


vec[i]





@JoachimW You can additionaly store reference/shared_ptr to the vector in the lambda. This will make it usable, right?
– bartop
27 mins ago





Yes, that goes into the right direction
– Joachim W
26 mins ago





@JoachimW Now A should work as persistent pointer. Even though I do not know what it is for ;)
– bartop
19 mins ago


A






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

VHIiFj6 U73rdHO87P24nqUoNR1kq1ddo0e7wddF,GYML8UlS Or9wlzX3,9hiVq,S l9MXoGMx5siiQxTI6cJvPC,FNZ 0Rpa
r cDoMPoK3TpzanIdrdHEV,61rmExFf8n3eIRUZi1VF,mDOxusaNjmt1,sgh28u1mMqFFSbyaf

Popular posts from this blog

Makefile test if variable is not empty

Visual Studio Code: How to configure includePath for better IntelliSense results

Will Oldham