Commit 11806783 authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

Add in appendix a notebook about std::string_view.

parent 67689ca1
......@@ -20,6 +20,8 @@
"* [Homemade exceptions](./HomemadeException.ipynb) just provides the instantiation of the class I personally use when I want to raise an exception; it's a direct follow-up of the section that [mentioned it](../5-UsefulConceptsAndSTL/1-ErrorHandling.ipynb#The-exception-class-I-use).\n",
"\n",
"* [Switch](./Switch.ipynb) is the less important one: it just explains `switch` statement and the syntax caveats you might encounter with them. It was mentioned in the [early notebook](../1-ProceduralProgramming/2-Conditions-and-loops.ipynb#switch-statement) about conditions.\n",
"\n",
"* [StringView](./StringView.ipynb) explains briefly the whereabouts of `std::string_view` which was introduced in C++ 17 - and which will be expanded to other types in C++ 20.\n",
"\n"
]
},
......@@ -80,5 +82,5 @@
}
},
"nbformat": 4,
"nbformat_minor": 2
"nbformat_minor": 4
}
{
"cells": [
{
"cell_type": "markdown",
"id": "451d5c67-1c82-4f19-9fd4-b7dd49bac7fb",
"metadata": {},
"source": [
"# [Getting started in C++](./) - [Stringview](./StringView.ipynb)"
]
},
{
"cell_type": "markdown",
"id": "bd83674b-5f88-4d28-b959-ba315588fa67",
"metadata": {},
"source": [
"C++ 17 introduced `std::string_view`, which basically introduces a sort of viewer over a string (not especially a `std::string`: it works basically as long as it's a chain of contiguous characters, where what is a *character* is defined as first template argument).\n",
"\n",
"Let's roll an example to illustrate how it works:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d6cc7d26-80ba-4c0a-a276-56f9d850bbbe",
"metadata": {},
"outputs": [],
"source": [
"#include <string>\n",
"#include <string_view>\n",
"#include <iostream>\n",
"\n",
"void print(std::string_view content)\n",
"{\n",
" std::cout << \"Content is '\" << content << \"'\" << std::endl;\n",
"}\n",
"\n",
"\n",
"std::string hello(\"Hello world from std::string!\");\n",
"\n",
"print(hello);\n",
"\n",
"print(\"Hello world!\");"
]
},
{
"cell_type": "markdown",
"id": "e565e634-7abb-403a-af47-b46e7e9936e5",
"metadata": {},
"source": [
"Prior to C++ 17, the usual way was to use `const std::string&` as parameter (passing a `std::string` directly would incur copies):"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f1562c99-1b25-4314-9903-1932571fe86d",
"metadata": {},
"outputs": [],
"source": [
"#include <string>\n",
"#include <iostream>\n",
"\n",
"void print_with_const_ref(const std::string& content)\n",
"{\n",
" std::cout << \"Content is '\" << content << \"'\" << std::endl;\n",
"}\n",
"\n",
"\n",
"std::string hello(\"Hello world from std::string!\");\n",
"\n",
"print_with_const_ref(hello);\n",
"print_with_const_ref(\"Hello world!\");"
]
},
{
"cell_type": "markdown",
"id": "4df1c364-df85-4a4d-a0d3-43218189354d",
"metadata": {},
"source": [
"So what did we gain exactly in the bargain?\n",
"\n",
"If you remember the discussion about *l-values* and *r-values* in the [notebook about move semantics](../5-UsefulConceptsAndSTL/5-MoveSemantics.ipynb), the construct used prior to C++ 17 doesn't necessarily make much sense: in our second call the argument `Hello world!` is clearly a r-value whereas a l-value would be expected given the prototype!"
]
},
{
"cell_type": "markdown",
"id": "414b36fb-0179-4a0f-a963-2c931c93e12a",
"metadata": {},
"source": [
"Let's write the same *without* the `const` to convince ourselves:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b7471040-bffb-4a48-8ea0-2ad1fddbf442",
"metadata": {},
"outputs": [],
"source": [
"#include <string>\n",
"#include <iostream>\n",
"\n",
"void print_with_ref(std::string& content)\n",
"{\n",
" std::cout << \"Content is '\" << content << \"'\" << std::endl;\n",
"}\n",
"\n",
"print_with_ref(\"Hello world!\"); // COMPILATION ERROR!"
]
},
{
"cell_type": "markdown",
"id": "f9dc26d5-1b95-4c75-8ca8-901e6962215e",
"metadata": {},
"source": [
"This time it doesn't work at all...\n",
"\n",
"So when we provide a r-value argument to a `const std::string&` parameter, the compiler does some magic to interpret it. This magic is not without cost: a `std::string` is allocated on the fly to store the content of the r-value.\n",
"\n",
"That is what `std::string_view` strives to correct: when it is used there are no such allocation involved.\n",
"\n",
"So whenever possible, using `std::string_view` instead of `const std::string&` is advised - provided of course your project is firmly grounded in C++ 17 or later.\n",
"\n",
"That doesn't mean there are no costs involved: when you are using `std::string_view`, you are essentially taking the responsability to ensure the memory area still exists (very similarly to the kind of contract you pass when you define a reference). [CppReference](https://en.cppreference.com/w/cpp/string/basic_string_view) illustrates this on a very basic case:\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "157f9843-02d4-4c7b-b062-f4403f911cd8",
"metadata": {},
"outputs": [],
"source": [
"// Beware: the code in this cell seems to disturb Xeus-cling ability to write to std::cout...\n",
"// A ticket has been emitted: https://github.com/jupyter-xeus/xeus-cling/issues/405\n",
"\n",
"#include <iostream>\n",
"#include <string>\n",
"#include <string_view>\n",
"\n",
"std::string_view bad(std::string(\"a temporary string\")); // \"bad\" holds a dangling pointer\n",
"\n",
"// Any use of bad here will result in undefined behaviour as the `std::string` was destroyed in \n",
"// previous line when it went out of scope!\n"
]
},
{
"cell_type": "markdown",
"id": "d8be6dd3-6ecf-4861-a556-35fe159e3445",
"metadata": {},
"source": [
"C++ 20 will expand on this possibility for other contiguous containers with [`std::span`](https://en.cppreference.com/w/cpp/container/span)."
]
},
{
"cell_type": "markdown",
"id": "d46d567d-50e9-4fef-a689-deaaff8d059a",
"metadata": {},
"source": [
"\n",
"© _CNRS 2016_ - _Inria 2018-2021_ \n",
"_This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_ \n",
"_The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "C++17",
"language": "C++17",
"name": "xcpp17"
},
"language_info": {
"codemirror_mode": "text/x-c++src",
"file_extension": ".cpp",
"mimetype": "text/x-c++src",
"name": "c++",
"version": "17"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment