-1

Can I get some advise? Instead of returning the vector from the function as a pointer or a reference, I am returning it as a string which contains the address. (I had good reason for this).

^That part was successful, the part I can't seem to figure out is, how to take that returned string(which holds an address of a vector) and make a new vector with it.

This is the vector (of type struct) that was passed from the function in a string containing its memory address:

vector<intructor> intruct;

Converting vector's address to a string: successful

string address;
stringstream ss;
ss << &depart;
ss >> address;
return address;

My attempt to convert it back in a new vector: failed

    vector<intructor> getIntructorVector(string filePath)
{
stringstream ss;
string address = VectorCreator(filePath);
vector<intructor> intruct;

ss << address;
ss >> &intruct;

return intruct;
}

If you need to know, this is what the vector holds:

struct intructor {
string name;
string dept;
int id;
};
Josh
  • 1
  • 2
  • And address is not an object. You cannot convert it to one. If and only if the vector is alive at that point, you can dereference a pointer to it. But you don't even have that, because you've stored it inside a string. This is incredibly convoluted. If you need a copy of the vector, design an interface that returns it. If you want access to a vector contained in a class, offer access to it by reference or to its iterators. – patatahooligan Sep 20 '18 at 01:12
  • 4
    *(I had good reason for this).* -- I would like to hear this "good reason". This is sounding more like an [XY Problem](http://xyproblem.info/). On a high-level, what are you really trying to accomplish? – PaulMcKenzie Sep 20 '18 at 01:14
  • 1
    @PaulMcKenzie I have a function that handles two different types of vectors struts depending on the input file. Since I can not have a return type for the function that will allow me to directly return either/or of the vectors, I tried playing around with pointers and references. I can't return it as a pointer directly from the function since the pointer has to have a type. The string method was a workaround in my head. – Josh Sep 20 '18 at 01:36
  • @Josh This is exactly what the XY problem is about. You could have asked about what you're goal is instead of how you attempted to accomplish your goal. If you have C++17, you could use [std::variant](https://en.cppreference.com/w/cpp/utility/variant), as illustrated [here](http://coliru.stacked-crooked.com/a/bb4db2c983e73e09) – PaulMcKenzie Sep 20 '18 at 01:50

3 Answers3

1

I'll give the traditional StackOverflow caveat of "you probably don't actually want to do this" -- manually manipulating pointers at all is generally discouraged in modern C++, and there are a lot of Bad Things that can happen between allocating your object and passing the string around containing its address. That being said, here's your problem:

&intruct, the address of intruct, is an rvalue -- you can't write to it. Your current code is essentially doing the following:

{
stringstream ss;
string address = VectorCreator(filePath);
vector<intructor> intruct;
vector<intructor>* intructPtr = &intruct;

ss << address;
ss >> intructPtr; // intruct has not been changed

return intruct;
}

Since your function is returning a vector (and not a reference or pointer to a vector), it seems that you want to create a copy of the vector being pointed to. In that case, you'll want to split it into two steps:

{
stringstream ss;
string address = VectorCreator(filePath);
vector<intructor>* intructPtr;

ss << address;
ss >> intructPtr; // intructPtr now points to the resource from VectorCreator

return *intructPtr; // returns a copy of the resource from VectorCreator
}

If you don't want to make a copy, then your function should return a reference vector<intructor>& or pointer vector<intructor>* -- though everything that you're doing is pretty dangerous and could easily end up referencing or pointing to an invalid location, segfaulting your program.

If you can't make VectorCreator return a smart pointer or the vector itself, be very careful that the vector doesn't get deleted or grow (potentially causing reallocation) before you've made a copy.

0

Try something like this instead:

std::vector<intructor> getIntructorVector(std::string filePath)
{
    std::string address = VectorCreator(filePath);
    std::istringstream iss(address);

    void *intruct;
    ss >> intruct;

    return *static_cast<std::vector<intructor>*>(intruct);
}

Assuming:

  1. you are NOT passing the std::string across process boundaries. A memory address owed by one process is NOT valid in another process.

  2. the original std::vector is still alive in memory when getIntructorVector() is called, otherwise you will have a dangling pointer so dereferencing it will be undefined behavior.

If either of these assumptions is NOT true, then what you are attempting to do CANNOT be done this way. You will have to serialize the entire vector data to a string, and then deserialize the string to a new vector, for example:

std::ostream& quoted(std::ostream &out, const std::string &s)
{
    out << '"';
    for(size_t x = 0; x < s.size(); ++x)
    {
        char c = s[x];
        if ((c == '"') || (c == '\\'))
            out << '\\';            
        out << c;
    }
    out << '"';
    return out;
}

...

size_t size = intruct.size();

std::ostringstream oss;
oss << size;

for(size_t x = 0; x < size; ++x)
{
    intructor &i = intruct[x];
    out << ' '; quoted(out, i.name);
    out << ' '; quoted(out, i.dept);
    out << ' ' << i.id;
}

return oss.str();

std::istream& unquoted(std::istream &in, std::string &s)
{
    if (in >> std::ws)
    {
        if (in.peek() == '"')
        {
            in.ignore();

            s.clear();

            char c;
            while (in.get(c))
            {
                if (c == '\\')
                {
                    if (!in.get(c))
                        break;
                }
                else if (c == '"')
                    break;
                s += c;
            }
        }
        else
            in >> s;
    }

    return in;
}

vector<intructor> getIntructorVector(string filePath)
{
    string data = VectorCreator(filePath);
    istringstream iss(data);
    string s;

    size_t size = 0;
    iss >> size;

    vector<intructor> intruct;
    intruct.reserve(size);

    for(size_t x = 0; x < size; ++x)
    {
        intructor i;

        unquoted(iss, i.name);
        unquoted(iss, i.dept);
        iss >> i.id;
        if (!iss) break;

        intruct.push_back(i);
    }

    return intruct;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Darn, wish it could've been this easy. I guess I am passing the string across process boundaries, rip. Thanks. – Josh Sep 20 '18 at 01:46
0

This all seems a little unorthodox tbh. It can work but only if you are sure the original vector will remain valid throughout the procedure. The address inside the string only points to the original vector after all.

struct intructor {
    std::string name;
    std::string dept;
    int id;
};

std::string vec_to_address(std::vector<intructor> const& v)
{
    std::ostringstream oss;
    oss << &v;
    return oss.str();
}

std::vector<intructor>* address_to_vec_ptr(std::string const& s)
{
    void* vp;
    std::istringstream(s) >> vp;
    return reinterpret_cast<std::vector<intructor>*>(vp);
}

int main()
{
    std::vector<intructor> v;
    v.push_back({"Name A", "Dept A", 1});
    v.push_back({"Name B", "Dept B", 2});
    v.push_back({"Name C", "Dept C", 3});

    auto address = vec_to_address(v);

    auto pointer = address_to_vec_ptr(address);

    for(auto const& i: *pointer)
        std::cout << i.name << '\n';

    // if you want a copy of the original vector you can do that
    // like this:
    auto copy_of_original = *pointer;
}

Output:

Name A
Name B
Name C
Galik
  • 47,303
  • 4
  • 80
  • 117