Lifetime of a temporary

142 views Asked by At

I am encountering some sporadic crashes when calling into a C++ library (not under my control) from C#.

The internal code of the C++ library is roughly like this:

#include <string>
#include <memory>

class Holder {
    public:
    static std::shared_ptr<Holder> create() {
        return std::make_shared<Holder>();
    }

    const std::string& getRef() {
        return value;
    }

    private:
    std::string value;
};

extern "C" void getRef(std::string& v) {
    auto h = Holder::create();
    v = h->getRef();
}

getRef is called from C# via P/invoke with no special marshalling.

Is this guaranteed to work? h goes out of scope at the end of getRef, but a reference to its member value is held and passed on. Is this reference still valid when being access on the C# side?

1

There are 1 answers

2
Christian Stieber On BEST ANSWER

The C++ part is fine.

v = h->getRef();

getRef returns a reference to a string that will be valid until h is killed off, which happens at the end of the function. However, the string is copied into the v string in this line, so no problem.

h goes out of scope at the end of getRef, but a reference to its member value is held and passed on.

That's where you are wrong; that reference is not passed on to anything.


EDIT: concerning the comments that this doesn't copy anything, try this:

#include <string>
#include <iostream>

const std::string& getRef()
{
    static const std::string result("success!");
    return result;
}

void test(std::string& v)
{
    v=getRef();
}

int main()
{
    std::string string="failure!";
    test(string);
    std::cout << string << std::endl;
    return 0;
}
stieber@gatekeeper:~ $ g++ Test.cpp; ./a.out
success!

Basically, while a reference is functionally similar to a pointer, it can't be assigned to: if you assign to a reference, you're always assigning to the object that's being referenced.