【问题标题】:C++ Segmentation fault while dereferencing a void pointer to a vector取消引用指向向量的 void 指针时出现 C++ 分段错误
【发布时间】:2020-03-20 16:03:48
【问题描述】:
#include <iostream>
#include <vector>
#include <mutex>

struct STRU_Msg
{
    std::string name;
    void *vpData;
};

class CMSG
{
public:
    template <typename T>
    int miRegister(std::string name)
    {
        STRU_Msg msg;

        msg.name = name;
        msg.vpData = malloc(sizeof(T));
        msgtable.push_back(msg);

        std::cout << "registeratio ok\n";
        return 0;
    }

    template <typename T>
    int miPublish(std::string name, T tData)
    {
        for (int i = 0; i < msgtable.size(); i++)
        {
            if (!name.compare(msgtable[i].name))
            {
                (*(T *)msgtable[i].vpData) = tData;
                std::cout << "SUccess!\n";
                return 0;
            }
            else
            {
                std::cout << "cannot find\n";
                return 0;
            }
        }
    }

private:
    std::vector<STRU_Msg> msgtable;
};


int main()
{
    CMSG message;
    std::string fancyname = "xxx";
    std::vector<float> v;

    // message.miRegister< std::vector<float> >(fancyname);
    // for (int i = 0; i < 1000; i++)
    // {
    //     v.push_back(i);
    // }
    // std::cout << "v[0]: " << v[0] << ", v[-1]: " << v[v.size()-1] << '\n';
    // message.miPublish< std::vector<float> >(fancyname, v);

    for (int i = 0; i < 1000; i++)
    {
        v.push_back(i);
    }
    std::cout << "v[0]: " << v[0] << ", v[-1]: " << v[v.size()-1] << '\n';
    message.miRegister< std::vector<float> >(fancyname);
    message.miPublish< std::vector<float> >(fancyname, v);

    return 0;
}

我想要实现的是编写一个简单的发布/订阅(如 ROS)系统,我使用 void 指针,以便它适用于所有数据类型。这是简化的代码。

如果我发布一个 int,它可以正常工作,但真正让我困惑的是:

  1. 如果我传递一个长向量(如这段代码),它会给我 “分段错误(核心转储)”错误。
  2. 如果我定义了“注册”和“发布”之间的向量(例如 注释部分),此错误消失。
  3. 如果我使用更短的向量,比如大小为 10,无论我在哪里定义 它,我的代码运行顺利。

我在 Linux 中使用 g++。

请帮我修复我的代码并解释为什么会发生上述行为,谢谢!

【问题讨论】:

  • 为什么不在CMSG 中声明STRU_Msg 并使用T *tpData 而不是void *vpData
  • malloc 在 C++ 中的用例很少(这不是其中之一),更喜欢new... 但void* 也是一种代码味道。
  • 你的循环只迭代一个第一个元素......
  • 而您的“工作”代码只是您的代码的每个变体所表现出的未定义行为的一种可能输出。
  • 据我所知,您使用malloc 分配sizeof(std::vector&lt;float&gt;) 字节的内存,然后将其转换为std::vector&lt;float&gt;(以便将另一个向量复制到其中,是对std::vector&lt;float&gt;::operator=(...)) 的调用,并期待合理的结果。那行不通(它是UB),您需要实际构建第一个向量;使用new 而不是malloc

标签: c++ c++11 vector void-pointers


【解决方案1】:

您不能复制std::vector 或任何其他类似的重要类型。在对此类对象执行任何操作(甚至是赋值)之前,您需要使用 constructorplacement new construct 它。 p>

一种方法是

new(msgtable[i].vpData) T;

register 函数中执行此操作。

然后你可以像你一样分配一个值。

更好的是,根本不要使用malloc,使用(正常,非放置)new 分配您的对象。

然而,我强烈建议放弃void* 并转向基于模板的STRU_Msg 实现。如果您不想重新发明轮子,请使用std::any

【讨论】:

  • 谢谢,我把msg.vpData = malloc(sizeof(T));改成了new(msg.vpData) T;,其他的都一样,然后不管我把注册函数放在哪里,或者T是什么类型,总是出现分段错误,请帮忙!
  • @n33 你要么使用(malloc ANDplacement new),或者(非placement new而不是malloc (推荐))。
猜你喜欢
  • 2017-09-20
  • 1970-01-01
  • 1970-01-01
  • 2015-01-04
  • 1970-01-01
  • 2012-03-25
  • 1970-01-01
  • 2021-10-24
  • 2011-10-20
相关资源
最近更新 更多