Consider this example.
#include <optional>
#include <string>
#include <vector>
struct Person {
std::optional<std::string> name;
};
std::optional<std::vector<std::string>> makeNames() {
return {{"adam", "eve"}};
}
Person makePerson() {
auto names = makeNames();
return {
names ? std::make_optional(std::move((*names)[0])) : std::nullopt
};
}
- Are there any copies of strings (etc) made inside
makePerson? - Is there a way to statically assert/enfore that an expression doesn’t create a copy?
>Solution :
Are there any copies of strings (etc) made inside makePerson?
No, std::strings are not copied. However std::vectors and std::strings are moved.
std::string is moved only in std::make_optional to emplace into the optional returned by the function. This is impossible to avoid, because std::optional embeds the value it holds in itself. If that is not desired std::unique_ptr can be used instead.
std::strings would be copied only if std::vector was copied, not if it is moved. std::vector‘s move constructor will not move string elements either.
Is there a way to statically assert/enfore that an expression doesn’t create a copy?
No, you can however wrap std::string in a class that is non-copyable and then see whether compilation will fail when using that wrapped string instead as element type.
Similarly you can wrap std::vector to make it non-copyable from which not copying the strings would follow.
You can also replace the allocator for std::string or std::vector and observe where memory for strings is allocated or string objects are constructed. You could forbid string copy construction in the vector allocator.
With the standard allocator you can also replace global operator new/operator delete and observe memory allocation there. However, the compiler is permitted to elide calls to them under certain circumstances if it can provide for memory in other ways.
If the strings are short enough for SSO to be used, then observing memory allocations won’t help either.