4 ms·
No, it allocates explicitly when you do that. Vec and String are heap-allocated types, so whenever you use them, you know you're doing an allocation. In C++ yo
by geofft 5y ago
No, it allocates explicitly when you do that. Vec and String are heap-allocated types, so whenever you use them, you know you're doing an allocation.
In C++ you can write code like this:
#include <string>
#include <iostream>
void print(const std::string &s) {
std::cout << s << std::endl;
}
int main() {
print("Hello world!");
}
This compiles with no warnings, and at no point in the function "main" do you see that you're causing a memory allocation and a copy by implicitly converting your static message to a std::string, passing it to the function, and deallocating it. If you code-review "main", it doesn't look like you're doing an allocation because you're passing a const char *; if you code-review "print", it doesn't look like you're doing an allocation because you're accepting a std::string, which has already been allocated. So you get an extra, unneeded allocation in the chasm between the two, and it's very hard to track down the performance problem (or, in the worst case, a hang - memory allocation can block on flushing buffers or swapping things out, so you'd better not run into this situation in code that could itself be involved in writing to disk!).
Compare the equivalent Rust code:
fn print(s: &String) {
println!("{}", s);
}
fn main() {
print("Hello world!");
}
which produces a "mismatched types" error: "expected reference `&String`, found reference `&'static str`."
To get this to compile, you have to write something like print(&"Hello world!".to_owned()); , where you specifically instruct an allocation to happen.
The objection is to implicit allocations. Explicit allocations are fine.
- jcelerier 5y ago> This compiles with no warnings, and at no point in the function "main" do you see that you're causing a memory allocation and a copy by implicitly converting your static message to a std::string, passing it to the function, and deallocating it Such a warning would be a bug in this specific case as "Hello World!" is under the SSO size though - there is no call to malloc/new in this specific std::string creation. I fail to see how that is relevant though: the kernel does not use the C standard library - it's not going to use the standard C++ library either except maybe the freestanding, compile-time-only bits such as type_traits, concepts, ... In which case it is trivial to have a string type akin to rust's: class kstring { public: explicit kstring(const char* str, std::size_t len); private: const char* m_storage{}; std::size_t m_len{}; }; auto operator""_to_owned(const char* str, std::size_t len) { return kstring{str, len}; } void print(const kstring& str) { // ... } int main() { // fails: // print("foo"); // ok print("foo"_to_owned); } Here, the correct answer would be std::string_view anyways (or a custom c_string_view). > If you code-review "main", it doesn't look like you're doing an allocation because you're passing a const char *; if you code-review "print", it doesn't look like you're doing an allocation because you're accepting a std::string, which has already been allocated. My experience really disagrees with this part, every time I've been involved in code reviews, it was common knowledge that a function taking a const& or && can cause an allocation at the call site. It's barely a beginner mistake to not take it into account.