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?
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.