@EastonMan 看的新闻
+碎碎念
+膜大佬
+偶尔猫猫
+伊斯通听的歌
Daniel Lemire's blog
Safer code in C++ with lifetime bounds

For better performance in software, we avoid unnecessary copies. To do so, we introduce references (or pointers). An example of this ideas in C++ is the std::string_view class. As the name suggests, a std::string_view instance is merely a ‘view’: it points at some string, but it does not own or otherwise manage the underlying memory.

The downside is that we must track ownership: when the owner of the memory is gone, we should not be left holding the std::string_view instance. With modern tools, it is trivial to detect such bugs (e.g., using a sanitizer). However, it would be nicer if the compiler could tell us right away.

A few C++ compilers (Visual Studio and LLVM) support lifetime-bound annotation to help us. Let us consider an example. Suppose you would like to parse a URL (e.g., ‘https://www.google.com/path’), but you are only interested in the host (e.g. ‘www.google.com’). You might write code like so using the ada-url/ada parsing library:
std::string_view get_host(std::string_view url_string) {
  auto url = ada::parse(url_string).value();
  return url();
}

This code is not generally safe. The parser will store the result of the parse inside a temporary object but you are returning an std::string_view which points at it. You have a dangling reference.

To get a recent version of LLVM/clang (18+) to warn us, we just need to annotate the function get_host like so:
#ifndef __has_cpp_attribute
    #define ada_lifetime_bound
#elif __has_cpp_attribute(msvc::lifetimebound)
    #define ada_lifetime_bound [[msvc::lifetimebound]]
#elif __has_cpp_attribute(clang::lifetimebound)
    #define ada_lifetime_bound [[clang::lifetimebound]]
#elif __has_cpp_attribute(lifetimebound)
    #define ada_lifetime_bound [[lifetimebound]]
#else
    #define ada_lifetime_bound
#endif

...

std::string_view get_host() const noexcept ada_lifetime_bound;

And then we get a warning at compile time:
fun.cpp:8:10: warning: address of stack memory associated with local variable 'url_aggregator' returned [-Wreturn-stack-address]
    8 |   return url_aggregator.get_host();

It is hardly perfect at this point in time. It does not always warn you, but progress is being made. This feature and others will help us catch errors sooner.

Credit: Thanks to Denis Yaroshevskiy for making me aware of this new compiler feature.

source
Daniel Lemire's blog
Does C++ allow template specialization by concepts?

Recent versions of C++ (C++20) have a new feature: concepts. A concept in C++ is a named set of requirements that a type must satisfy. E.g., ‘act like a string’ or ‘act like a number’.  When used in conjunction with templates, concepts can be quite nice. Let us look at an example. Suppose that you want to define a generic function ‘clear’ which behaves some way on strings and some other way on other types. You might use the following code:
template <typename T>
void clear(T & t);

template <typename T>
concept not_string =
!std::is_same_v<T, std::string>;

template <>
void clear(std::string & t) {
  t.clear();
}

template <class T>
void clear(T& container) requires not_string<T> {
  for(auto& i : container) {
    i = typename T::value_type{};
  }
}


We have a generic clear function that takes a reference to any type T as an argument. We define a concept not_string which applies to any type expect std::string. We specialize for the std::string case: template <> void clear(std::string & t) { t.clear(); }: It directly calls the clear() member function of the string to empty its contents. Next we define template void clear(T& container) requires not_string { ... }: it is a generic implementation of clear for any type T that satisfies the not_string concept. It iterates over the container and sets each element to its default value. When you call clear with a std::string, the specialized version is used, directly calling std::string::clear(). For any other type that satisfies the not_string concept (i.e., is not a std::string), the generic implementation is used. It iterates over the container and sets each element to its default value. This assumes that T is a container-like type with a value_type and iterator support.

There are easier ways to achieve this result, but it illustrates the idea.

Up until recently, I thought that the template with the ‘requires’ keyword was a template specialization, just like when you specialize the template for the std::string type.

Unfortunately, it may be more complicated. Let us repeat exactly the same code but we put the clear function in a class ‘A’:
struct A {
    template <typename T>
    void clear(T & t);
};

template <>
void A::clear(std::string & t) {
  t.clear();
}

template <class T>
void A::clear(T& container) requires not_string<T> {
  for(auto& i : container) {
    i = typename T::value_type{};
  }
}


This time, your compiler might fail with the following or the equivalent:
out-of-line definition of 'clear' does not match any declaration in 'A'

You might fix the issue by adding the template with the constraint to the class definition.
struct A {
    template <typename T>
    void clear(T & t);
    template <class T>
    void clear(T& container) requires not_string<T>;
};

I find this unpleasant and inconvenient because you must put in your class declaration all of the concepts you plan on supporting. And if someone wants to support another concept, they need to change your class declaration to add it.

source
Matt Keeter
Beating the compiler

source
(author: Matt Keeter (matt.j.keeter@gmail.com))
或者写一篇《敏捷香山不敏捷》
Easton Meow | 是满满
明天写篇博客
再写一篇《为什么科研不能使用RTL》
香山gem5无法支撑体系结构科研
明天写篇博客
什么gem5用不了一点
明天开始学习
发文章还得看chanpsim
Matt Keeter
Raven

A flexible Uxn + Varvara emulator

source
(author: Matt Keeter (matt.j.keeter@gmail.com))
Back to Top