-1
#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;
}

What I want to achieve is to write a simple publish/subscribe (like ROS) system, I use void pointer so that it works for all data type. This is the simplified code.

If I publish an int, it works fine, but what really confuse me are:

  1. If I pass a long vector (like this code), it gave me the "segmentation fault (core dump)" error.
  2. If I define the vector between "register" and "publish" (i.e. like the commented part), this error goes away.
  3. If I use a shorter vector, like size of 10, no matter where I define it, my code run smoothly.

I use g++ in Linux.

Please help me fix my code and explain why above behaviors will happen, thanks in ahead!

n33
  • 383
  • 4
  • 13
  • Why don't you declare `STRU_Msg` inside `CMSG` and use `T *tpData` instead of `void *vpData`? – goodvibration Nov 25 '19 at 11:20
  • 2
    `malloc` has really few use cases in C++ (and this one is not one of them), prefer `new`... but `void*` is also a code smell. – Jarod42 Nov 25 '19 at 11:21
  • And your loop iterates only one first element... – Jarod42 Nov 25 '19 at 11:23
  • And your "working" code is just one possible output of undefined behavior that each variant of your code exhibit. – Jarod42 Nov 25 '19 at 11:25
  • 3
    As far as I can tell, you're using `malloc` to allocate `sizeof(std::vector)` bytes of memory, then later casting this to `std::vector` (in order to copy another vector into it, which is a call to `std::vector::operator=(...)`) and expecting sensible results. That won't work (it's UB), you need to actually construct the first vector; use `new` instead of `malloc`. – Stu Nov 25 '19 at 11:27
  • emmm..I will think about placing template inside the class. In the meantime, can you provide more specific example about how to use new to replace malloc? – n33 Nov 25 '19 at 13:12

1 Answers1

1

You cannot copy std::vector or any other non-trivial type like that. Before you do anything (even assignment-to) with such an object, you need to construct it using a constructor and placement new.

A way to do this would be

new(msgtable[i].vpData) T;

Do this in the register function.

Then you can assign a value as you do.

Still better, do not use malloc at all, allocate your object with (normal, non-placement) new.

I however strongly suggest ditching void* and moving to a template based implementation of STRU_Msg. If you don't feel like reinventing the wheel, just use std::any.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • Thanks, I changed `msg.vpData = malloc(sizeof(T));` to `new(msg.vpData) T;` and leave everything else the same, then I always get the segmentation error no matter where I place the register function or what type T is, please help! – n33 Nov 25 '19 at 13:09
  • @n33 You *either* use (malloc **AND** placement new), *or* (non-placement new instead of malloc (recommended)). – n. m. could be an AI Nov 25 '19 at 13:36