最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - How to convert std::string_view to const std::string& - Stack Overflow

programmeradmin3浏览0评论

I'm developing a dynamic library, and for ABI-stability, I'm using a std::string_view-like class for passing read-only, non-owning strings.

A third-party library I'm using under the hood uses const std::string& for such purposes, and therefore I have to do something like std::string { view.data(), view.size() } whenever I call into that library, which incurs an unnecessary allocation.

Is there a way to handle this conversion without relying on compiler-specific std::string implementation details?

I think I can potentially use string interning or some form of caching if I know the number of strings I'll deal with is relatively small. However, this is not the case for my library because the user may pass arbitrary strings.

Using a custom allocator would make the string a different type, so that is not viable either.

I'm developing a dynamic library, and for ABI-stability, I'm using a std::string_view-like class for passing read-only, non-owning strings.

A third-party library I'm using under the hood uses const std::string& for such purposes, and therefore I have to do something like std::string { view.data(), view.size() } whenever I call into that library, which incurs an unnecessary allocation.

Is there a way to handle this conversion without relying on compiler-specific std::string implementation details?

I think I can potentially use string interning or some form of caching if I know the number of strings I'll deal with is relatively small. However, this is not the case for my library because the user may pass arbitrary strings.

Using a custom allocator would make the string a different type, so that is not viable either.

Share Improve this question edited Apr 6 at 20:08 TylerH 21.1k79 gold badges79 silver badges114 bronze badges asked Mar 10 at 16:57 dw218192dw218192 6266 silver badges13 bronze badges 5
  • 3 A std::string is owning. You can't do anything about it, since it will always copy the data you pass in – Raildex Commented Mar 10 at 16:59
  • 2 Less typing: std::string { view.data(), view.size() } -> std::string { view } – 3CxEZiVlQ Commented Mar 10 at 17:01
  • 5 For as long as that library demands const std::string&, it's probably wisest for your code to demand the same. std::string_view is great, but converting a codebase to use it should start at the endpoints. Consider telling the library authors that their interface imposes an unnecessary cost because of const std::string&. – Drew Dormann Commented Mar 10 at 17:14
  • Is it useful to characterise your View so that you also know if it originated from the full length of a std::string? In those cases, you could effectively pass through the original const std::string. In any case you may have the issue that the library expects the string to be zero terminated, if it is a lighweight C++ wrapper round C implementation. – Gem Taylor Commented Mar 10 at 17:15
  • Beware premature micro optimisations. You might not have a performance problem at all. – catnip Commented Mar 10 at 23:45
Add a comment  | 

3 Answers 3

Reset to default 9

The "efficient converting" is not defined, so I guess the OP assumes avoiding copying a buffer pointed by a string view. This is impossible in all cases.

  1. std::string_view::data() returns a pointer to a buffer that is not necessarily null-terminated.
  2. std::string::data() returns a null-terminated array.

std::string must append the null to a string view buffer, it can be made only after copying a buffer pointed by a string view.

Efficiency has many forms, performance wise there is not much you can do.
However you can make your code more like you want (and move the conversion to only one place in your code).

Provide an overload of the function provided by the 3rd party that does accept a std::string_view and constructs a temporary std::string and calls the original function. E.g. https://godbolt./z/1r5q8dnEG

#include <string>
#include <string_view>
#include <iostream>
#include <unordered_map>

// library provided
void f(const std::string& string)
{
    std::cout << string;
}

// Make your own "proxy" for the third party library
// by providing overloads :)
void f(std::string_view sv)
{
    f(std::string{sv});
}

int main()
{
    std::string_view sv{"string_view"};
    f(sv);
}

you can reserve a string to use just for that purpose, if that library's function is not reentrant. (you are sure it won't call back into your code while it is running, like std::unordered_map<std::string, int>::find before C++20

#include <string>
#include <string_view>
#include <iostream>
#include <algorithm>

// library
void library_func(const std::string& string)
{
    std::cout << string;
}

void my_func(std::string_view sv)
{
    thread_local std::string thread_local_str;
    thread_local_str.clear();
    thread_local_str.reserve(sv.size());
    std::copy(sv.begin(), sv.end(), std::back_inserter(thread_local_str));
    library_func(thread_local_str);
}

int main()
{
    std::string_view sv{ "string_view" };
    my_func(sv);
}

if it is reentrant then you can use a pool of strings for this. but this would lead to a slow memory leak because the memory is not being returned back to the global allocator, so you would be better off making a new string on each call than using a pool.


for attribution, used @PepijnKramer answer as a starting point.

发布评论

评论列表(0)

  1. 暂无评论