将 void* 转换为 (vector<void*>*) 时出现问题

problem casting a void* to a (vector<void*>*)

提问人:Alessandro Savona 提问时间:7/11/2023 最后编辑:Remy LebeauAlessandro Savona 更新时间:7/12/2023 访问量:102

问:

我目前正在研究一个复杂的逻辑,其中我有一个具有这些值:map<string,void*>

string mystring[10] = {"key1","key2","keyN"};
for(string s: mystrings){
    vector<void*> v;
    v.push_back(this);
    v.push_back(&s);
    map.insert({s,&v});
}

在某个时刻,我必须将我的传递给触发回调的计时器:vector

mytimer(int milliseconds, mycallback,void* (parameter of the callback));
this->mytimer(1000,MY_CALLBACK,map.at("Key1"));

问题出在回调中:

static void MY_CALLBACK(void*);
void MY_CALLBACK(void* args){
    auto obj = (vector<void*>*) args;
    auto key = (string*) obj->at(1);
    auto logic = (MY_CLASS *) obj->at(0);
    some logic;
}

程序崩溃,因为当我尝试获取 的任何值时出现“超出范围”错误。vector

问题是什么?

C++ 向量 转换 回调 void-pointers

评论

4赞 PaulMcKenzie 7/11/2023
v.push_back(&s);-- 您正在添加指向临时变量的指针。您认为每次循环迭代时该变量会发生什么?
3赞 Richard Critten 7/11/2023
map.insert({s,&v});将局部变量的地址(添加到映射中)添加,然后该变量超出范围,留下一个悬空的指针。v
2赞 Edward Strange 7/11/2023
这种编码风格,有很多指针和投射,是一种非常过时的做事方式,人们不再做这些事情,因为众所周知,要做对是很困难的——对于初学者来说,甚至很难开始理解。使用 std::any 或 variant 的建议怎么强调都不为过。如果你被困在一些 std::any 不可用的旧地狱中,那么使用 boost,或者如果你阅读 boost 版本的文档,它实际上很容易实现。这样做的唯一理由是,如果你被告知这样做——然后我会在其他地方找工作,因为不必要的挫败感很糟糕。
3赞 Ted Lyngmo 7/11/2023
猜测何时用 C++ 编程通常会带来很多悲伤。这不是一种非常宽容的语言。
4赞 Marek R 7/11/2023
这是XY问题。此代码已损坏,无法修复。如果你解释它应该做什么/为什么你需要这个,你会得到适当的解决方案。例如,这是从哪里来的?MY_CALLBACK

答:

4赞 463035818_is_not_an_ai 7/11/2023 #1

这里

for(string s: mystrings){
     vector<void*> v;
     v.push_back(this);
     v.push_back(&s);
     map.insert({s,&v});
   }

您正在插入指向一个向量的指针,该向量的生存期在迭代结束时结束。地图中的指针是无用的。这是一个悬而未决的指针。稍后取消引用指针会导致未定义的行为。

1赞 Remy Lebeau 7/12/2023 #2

您存储的是指针指向在有机会使用指针之前被销毁的对象。

您的循环正在迭代数组,将指向每个数组副本的指针推送到 .副本在当前小版本结束时被销毁。而且,它本身是每次迭代的本地函数,因此在将指向它的指针推入 .forstring[]stringvectorvectormap

对于您正在尝试的内容,请尝试更多类似的东西:

using var = std::variant<MY_CLASS*, std::string>;
using vec = std::vector<var>;

...

std::map<std::string, vec> my_map;

...

std::string mystring[10] = {"key1", "key2", "keyN"};
for(auto& s: mystrings){
    vec v;
    v.emplace_back(this);
    v.emplace_back(s);
    my_map.insert({s, std::move(v)});
}

...

this->mytimer(1000, MY_CALLBACK, &(my_map.at("key1")));

...

void MY_CALLBACK(void* args){
    auto v = static_cast<vec*>(args);
    auto logic = std::get<MY_CLASS*>(v->at(0));
    auto key = std::get<std::string>(v->at(1));
    // use logic and key as needed...
}

请注意,这假定您在计时器运行时没有修改 的内容。如果这样做,则需要动态创建,例如:mapvector

using var = std::variant<MY_CLASS*, std::string>;
using vec = std::vector<var>;

...

std::map<std::string, std::unique_ptr<vec>> my_map;

...

std::string mystring[10] = {"key1", "key2", "keyN"};
for(auto& s: mystrings){
    auto v = std::make_unique<vec>();
    v->emplace_back(this);
    v->emplace_back(s);
    my_map.insert({s, std::move(v)});
}

...

this->mytimer(1000, MY_CALLBACK, my_map.at("key1").get());

...

void MY_CALLBACK(void* args){
    auto v = static_cast<vec*>(args);
    auto logic = std::get<MY_CLASS*>(v->at(0));
    auto key = std::get<std::string>(v->at(1));
    // use logic and key as needed...
}