How to correctly clone a string from a struct in a C library into a new memory address?

三世轮回 提交于 2021-02-19 06:48:05

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!