问题
I'm trying to make a clone of my C++ object, which is a wrapper around a C 'class'. I want to API to look like this:
LibrdfUri uri("http://uri.com");
LibrdfUri uri_clone = uri.clone(); // same value but points to different memory address
Here is my clone function
...
librdf_uri *LibrdfUri::get() const { // librdf_uri is the C type that I am wrapping
return librdf_uri_.get(); // librdf_uri_ is a unique pointer. .get returns the raw pointer
}
LibrdfUri LibrdfUri::clone() const {
unsigned char * cstr = librdf_uri_as_string(get()); // C library utility. Returns the value of the string
int l = strlen((const char*)cstr);
char *uri_string = new char[l+1];
std::strcpy(uri_string, (const char*)cstr);
return LibrdfUri((const char *) uri_string); //uri_string now contains the same characters as cstr
}
But my test case still fails:
TEST_F(LibrdfUriTests, TestClone) {
LibrdfUri uri("http://uri.com");
LibrdfUri uri_clone = uri.clone();
ASSERT_STREQ(uri.str().c_str(),
uri_clone.str().c_str()); // test passes
ASSERT_NE(&uri, &uri_clone); // test passes
ASSERT_NE(uri.get(), uri_clone.get()); // test fails, the addresses are the same.
}
Can anybody see what is going on here?
Edit:
Here is the full class of LibrdfUri
, in case its helpful.
class LibrdfUri {
struct deleter {
void operator()(librdf_uri *ptr);
};
std::unique_ptr<librdf_uri, deleter> librdf_uri_;
public:
LibrdfUri() = default;
[[nodiscard]] std::string str() const;
explicit LibrdfUri(const std::string &uri);
explicit LibrdfUri(librdf_uri *uri);
[[nodiscard]] librdf_uri *get() const;
LibrdfUri clone() const;
};
// implementation
void LibrdfUri::deleter::operator()(librdf_uri *ptr) {
librdf_free_uri(ptr);
}
LibrdfUri::LibrdfUri(const std::string &uri) {
librdf_uri_ = std::unique_ptr<librdf_uri, deleter>(
librdf_new_uri(World::getWorld(), (const unsigned char *) uri.c_str())
);
}
std::string LibrdfUri::str() const {
auto cstr = (unsigned char *) librdf_uri_as_string(get());
std::string s = (const char *) cstr;
return s;
}
librdf_uri *LibrdfUri::get() const {
return librdf_uri_.get();
}
LibrdfUri::LibrdfUri(librdf_uri *uri)
: librdf_uri_(std::unique_ptr<librdf_uri, deleter>(uri)) {}
Edit2
On a suggestion from a commenter I have changed my clone
function to
LibrdfUri LibrdfUri::clone() const {
return LibrdfUri(librdf_new_uri_from_uri(get()));
}
However the clone still doesnt behave as intended::
LibrdfUri uri("http://uri.com");
LibrdfUri uri_clone = uri.clone();
std::cout << &uri << ", " << &uri_clone << std::endl;
std::cout << uri.get() << ", " << uri_clone.get() << std::endl;
Outputs:
0x7ffc46e17400, 0x7ffc46e17408
0x55c0cf693120, 0x55c0cf693120
edit 3
Also, the output of
LibrdfUri uri1("http://uri.com");
LibrdfUri uri2("http://uri.com");
std::cout << &uri1 << ", " << &uri2 << std::endl;
std::cout << uri1.get() << ", " << uri2.get() << std::endl;
is
0x1fff000560, 0x1fff000568
0xed98a60, 0xed98a60
But the output of
LibrdfUri uri1("http://uri1.com");
LibrdfUri uri2("http://uri2.com");
std::cout << &uri1 << ", " << &uri2 << std::endl;
std::cout << uri1.get() << ", " << uri2.get() << std::endl;
is
0x7fff89c40120, 0x7fff89c40128
0x55a2e4c12120, 0x55a2e4c12470
来源:https://stackoverflow.com/questions/61992723/how-to-correctly-clone-a-string-from-a-struct-in-a-c-library-into-a-new-memory-a