Rust does not allocate implicitly when you use Vec or String (or any other container) ? come on..
Rust does not allocate implicitly when you use Vec or String (or any other container) ? come on..
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.
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.
The new() functions for these types are const (ie they can be evaluated at compile time) and produce an "empty" placeholder.
Because Rust's Strings don't have NUL termination, the empty string doesn't need any backing storage, likewise for an empty vector.
When (and more importantly in many programs if) you actually add something to the string or vector that may prompt an allocation, but you called an explicit method to do that, so it oughtn't to come as any surprise.