0

I have a union of two std::vectors and when I call push_back i get a read access violation. I'm pretty new to unions so I bet I'm doing something wrong with them. Any ideas why this is happening?

struct Row
{
    char order_id[30];
    char garbage[994];
    Row() {}
    ~Row() {}
};

struct Row_List
{
    union
    {
        std::vector<Row> divided_row;
        std::vector<char*> combined_row;
    };
    Row_List() {}
    ~Row_List() {}
};

int main(void)
{
    Row_List results;

    char current_row[1024];

    //initialize row to null
    for (int i = 0; i < 1024; ++i)
    {
        current_row[i] = '\0';
    }

//error happens here
    results.combined_row.push_back(current_row);

    return 0;
}

EDIT: my final overall goal is to simplify the SQLGetData (in SQL.h) method by getting it to write the results into a vector of Row. currently, you just have to give it a pointer and it will write the results into that memory location. I wanted a function to return the result into a struct that I specify but each SQL query might have different fields in the result. I thought unions would let me write the results into a char array but then read it as a struct i specify.

I might run an SQL query that returns 10 rows and each row contains an integer and a char array. I might also run a query that returns 100 rows and each row contains a boolean, an integer, and two char arrays.

In the first example I want the results in a vector of structs which contain an integer and a char array. In the second example I want a results in a vector of structs that contain a boolean, an integer, and two char arrays.

The main issue being I want a generic way to write into any struct. I'm fine with passing a list of data type sizes though.

example function to do this:

bool SQL_Query::write_results(std::vector<std::array<char, 1024> >& results_vector)
{
    /*
    user makes a union of (a vector of long chars, and a vector of several small chars, ints etc.)
    they pass the vector of long chars into this function
    */

    //if not connected or if the query isnt successful or if the row structure hasnt been set then do nothing
    if (!m_connected || !m_query_successful || !m_row_structure_set)
    {
        return false;
    }

    //for each row
    while (SQLFetch(m_SQL_statement_handle) == SQL_SUCCESS)
    {
        //declare a single row
        std::array<char, 1024> current_row;

        //initialize row to null
        for (int i = 0; i < 1024; ++i)
        {
            current_row[i] = '\0';
        }

        char* current_location = &current_row[0];

        //for each column
        for (unsigned int current_col = 1; current_col <= m_memory_size_list.size(); ++current_col)
        {
            //get next results max memory size
            int current_buffer_size = m_memory_size_list.at(current_col - 1);

            //write that into current_row at current_location
            SQLGetData(m_SQL_statement_handle, current_col, SQL_C_DEFAULT, current_location, current_buffer_size, NULL);

            //move to next write location in current_row by adding the current max memory size to 
            current_location += current_buffer_size;
        }

        //add single row to results vector
        results_vector.push_back(current_row);
    }

    //return true if everything went right
    return true;
}
timrau
  • 22,578
  • 4
  • 51
  • 64
R. Binter
  • 221
  • 1
  • 8
  • 7
    You can't use non-POD types in a `union` (well, not the way you are, anyway). Even if you could, `std::vector` and `std::vector` are unrelated types, so modifying one will corrupt the other. What are you really trying to accomplish here? – Remy Lebeau Dec 04 '18 at 20:36
  • 2
    Use `std::variant` instead. – Matthieu Brucher Dec 04 '18 at 20:37
  • 1
    @RemyLebeau this is not true since C++11, unions can have non-POD members. – SergeyA Dec 04 '18 at 20:37
  • The compiler must have been screaming at you. – Matthieu Brucher Dec 04 '18 at 20:37
  • @SergeyA I'm aware of that, but it doesn't change what I said. – Remy Lebeau Dec 04 '18 at 20:38
  • Unions and non-trivial types are tricky. I think you should explicitly construct the instances somehow. I recommend using std::variant instead – JVApen Dec 04 '18 at 20:38
  • @RemyLebeau not after the edit. I have seen and answered your comment before you edited it. – SergeyA Dec 04 '18 at 20:38
  • 2
    @MatthieuBrucher I doubt `std::variant` will help OP, as it will suffer from the same design flaw - it seems to be OP is trying to alias one vector with another, which is, of course, not possible. I think, as of now the question has a terrible smell of XY problem and I am considering closing the question as such. – SergeyA Dec 04 '18 at 20:40
  • 2
    You need to use placement new on the union member before you use it (this will call the constructor of the vector). This is the way that non-POD types can be used in an union. – geza Dec 04 '18 at 20:42
  • 4
    I'm voting to close this question as off-topic because this question looks like XY problem more than anything else. The question can not be answered in full unless OP explains what is the ultimate goal here. – SergeyA Dec 04 '18 at 20:42
  • 1
    What are your trying to achieve with this code? If we know that we can offer some solid advice on how to handle it. – NathanOliver Dec 04 '18 at 20:43
  • What makes you believe he wants to use unions as a hidden reinterpret cast? I don't deduce this from the question – JVApen Dec 04 '18 at 20:44
  • @JVApen I have this gut feeling. Could be wrong, unfortunately, OP doesn't offer any clarification. – SergeyA Dec 04 '18 at 20:45
  • In case you're wondering, [What is the XY problem?](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) – user4581301 Dec 04 '18 at 20:45
  • ok I added some clarification but I probably need to add more. You are correct, I asked the wrong question because I thought I could simplify my question a bit by excluding my final goal. – R. Binter Dec 04 '18 at 20:54

1 Answers1

1

Before you use a non-trivial type in a union, you must create it by calling placement new on it:

new(&results.combined_row) std::vector<char*>();

Then you can use it:

results.combined_row.push_back(current_row);

After usage, you need to call the destructor:

results.combined_row.~vector();

Note, that you are not allowed to access other union members, while combined_row is created.

geza
  • 28,403
  • 6
  • 61
  • 135
  • Not an answer to OP question after edit. – SergeyA Dec 04 '18 at 20:59
  • 1
    @SergeyA: you are a nice guy. – geza Dec 04 '18 at 21:00
  • 1
    Proud to be, thank you. – SergeyA Dec 04 '18 at 21:00
  • @SergeyA The question perfectly answers why the OP had problems using the vector – Tootsie Dec 04 '18 at 21:28
  • @Tootsie we already established this was not the problem OP was trying to solve, and the answer doesn't solve OP's problem. – SergeyA Dec 04 '18 at 22:04
  • @SergeyA: We still don't know what OP's problem is. If OP wants something like type-punning, then that's a **very** different question, OP should create a new one. Modifying a question to mean something else is unfair. And it is unfair to downvote an answer (which actually solves the original problem), which is given some minutes after the modification. – geza Dec 04 '18 at 22:16
  • @geza I think it is clear that currently your answer doesn't answer the question. Edits/no edits, this is just not the answer! That's why I downvoted it. I believe, beside being factually correct, the answer should solve the problem (which is clear right now, btw. It is aliasing, as I suspected some time ago). At this point, I believe the best course of action would be to either rephrase the answer with the problem in mind, or remove it altogether. My downvote is an expression of this belief. I see nothing unfair with this. – SergeyA Dec 04 '18 at 22:30
  • @SergeyA: You see nothing unfair about that someone worked on a answer, posted it, and then realize, that 3 minutes before the question had been modified to something else? Please... No. The best action would be to revert the question to its original form, and ask a new one for the updated problem. – geza Dec 04 '18 at 22:57