min-devkit outlet crash with prepended string

MIB's icon

I just started working with the min-devkit a little bit and I am running into a weird crash I don't quite understand (see code snippet below). I am on Sequoia 15.1.1 on a 2023 M3 using Max 8.6.5.

If I send something out an outlet, starting with a string followed by a single number (e.g. float), that works. Anything else seems to cause a crash.

What I am trying to do is add a string before a list of floats so I can use [route] in max to further process the output.

Furthermore, when I use a string followed by atoms

 model.send("data", data_atoms) 

I get an error stating:

No matching member function for call to 'push_back'

referring me to c74_min_outlet.h line 282

 // utility: queue an argument of any type for output
    template <typename argument_type>
    void queue_argument(const argument_type& arg) noexcept
    {
        m_accumulated_output.push_back(arg);
    }

this clearly treats m_accumulated_output as a vector since we are using the push_back() to add a value to the end of it. However, if I look at the type of m_accumulated_output it is of type atoms. (see line 434 in c74_min_outlet.h)

If I go to c74_min_atom.h it clearly states on line 319 that:

// We don't own the array of atoms, so we cannot do these operations:
    // insert
    // erase
    // push_back
    // push_front
    // pop_front
    // pop_back

I might have a fundamental misunderstanding here, but it looks like that if we deal with atoms we can't use .push_back(), but in queue_argument() from c74_min_outlet.h (line 282) we clearly use .push_back() to try to add something to atoms.

So, long story short: what is the correct way of sending something like:

std::vector<float> data = {....};
std::string routing = "data";

to_outlet.send(routing, data);

so in max I can use [route data] to process the output?

Thanks so much for your help!!!

Here are the different ways I have tried to use this and the results:

   // Handle "bang" message
    message<> bang{this, "bang", "Outputs the data.",
        MIN_FUNCTION {

            std::vector<float> entry = {7.4f};
            std::vector<float> entries = {1.0f, 2.0f, 3.0f};
            atoms data(entries.size());
            data = to_atoms(entries);

                //use vector directly => crash
            model.send(entries);  // => crash

            //convert vector to atoms => works
            model.send(data);  // ==> works

            model.send(to_atoms(entries));  // ==> works

                //use string with float => works
            model.send("data", 1.45f); // ==> works

            //use string with atoms (single float) => crash
            model.send("data", to_atoms(entry)); // ==> crash

                //use string with float vector => crash
            model.send("data", entries); // ==> crash

                //use string with atoms (multiple floats) => crash
            model.send("data", data);  // ==> crash

            return {};
        }
    };
JBG's icon

Yep, there are quite a few issues in terms of type safety in the current implementation of min::outlet::send. This is what I tend to do when I need to output keyword + vector:

message<> bang{this, "bang", MIN_FUNCTION {
    std::vector entries{1.0f, 2.0f, 3.0f};
    atoms atms{"data"};
    atms.reserve(entries.size() + 1);
    atms.insert(atms.end(), entries.begin(), entries.end());
    outlet_main.send(atms);

    return {};
}};

The atms.reserve(entries.size() + 1); is redundant here, but it's good practice if you don't know the size of the output beforehand

MIB's icon

Thanks! that works perfectly.