From 92988dda0dd1feb4dd977869dd002b9ea43e505e Mon Sep 17 00:00:00 2001 From: Ravi Prakash Date: Sun, 28 May 2023 16:03:35 +0530 Subject: [PATCH] Remove duplicate totw-3 and totw-5. --- _posts/2020-06-01-totw-5.md | 109 ------------------------------------ _posts/2022-11-16-totw-3.md | 96 ------------------------------- 2 files changed, 205 deletions(-) delete mode 100644 _posts/2020-06-01-totw-5.md delete mode 100644 _posts/2022-11-16-totw-3.md diff --git a/_posts/2020-06-01-totw-5.md b/_posts/2020-06-01-totw-5.md deleted file mode 100644 index 77b2e5ce..00000000 --- a/_posts/2020-06-01-totw-5.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: "Tip of the Week #5: Disappearing Act" -layout: tips -sidenav: side-nav-tips.html -published: true -permalink: tips/5 -type: markdown -order: "005" ---- - -Originally posted as TotW #5 on June 26, 2012 - - - -Updated 2020-06-01 - -Quicklink: [abseil.io/tips/5](https://abseil.io/tips/5) - - -*"Don't know what you got till it's gone." --Cinderella* - -Sometimes, in order to use a C++ library the right way, you need to understand -both the library and the language. So … what’s wrong with the following? - -
-// DON’T DO THIS
-std::string s1, s2;
-...
-const char* p1 = (s1 + s2).c_str();             // Avoid!
-const char* p2 = absl::StrCat(s1, s2).c_str();  // Avoid!
-
- -Both (`s1+s2`) and `absl::StrCat(s1,s2)` create temporary objects (in both -cases, strings, but the same rules apply for any objects). The member function -`c_str()` returns a pointer to data that lives as long as the temporary object. -How long does the temporary object live? According to the C++17 standard -[class.temporary], "Temporary objects are destroyed as the last step in -evaluating the full-expression that (lexically) contains the point where they -were created." (A "full-expression" is "an expression that is not a -subexpression of another expression"). In each example above, as soon as the -expression on the right side of the assignment operator was completed, the -temporary value was destroyed, and the return value from `c_str()` became a -dangling pointer. tl;dr? By the time you hit a semicolon (often sooner), the -temporary object is history. Yikes! How can you avoid this kind of problem? - -## Option 1: Finish Using the Temporary Object Before the End of the full-expression: - -
-// Safe (albeit a silly example):
-size_t len1 = strlen((s1 + s2).c_str());
-size_t len2 = strlen(absl::StrCat(s1, s2).c_str());
-
- -## Option 2: Store the Temporary Object. - -You’re creating an object (on the stack) anyway; why not hang on to it for a -while? This is cheaper than it might first appear. Because of something called -"return value optimization," (and move semantics on many value types, see -[Tip #77](/tips/77)) the temporary object will be constructed in the variable -you’re "assigning" it to, and won’t be copied: - -
-// Safe (and more efficient than you might think):
-std::string tmp_1 = s1 + s2;
-std::string tmp_2 = absl::StrCat(s1, s2);
-// tmp_1.c_str() and tmp_2.c_str() are safe.
-
- -## Option 3: Store a Reference to the Temporary Object. - -C++17 standard [class.temporary]: "The temporary to which the reference is bound -or the temporary that is the complete object of a sub-object to which the -reference is bound persists for the lifetime of the reference." - -Because of return value optimization, this usually isn’t any cheaper than -storing the object itself (Option 2), and it is potentially confusing or -worrisome (see [Tip #101](/tips/101)). (Exceptional cases that need to use -lifetime extension should be commented!) - -
-// Equally safe:
-const std::string& tmp_1 = s1 + s2;
-const std::string& tmp_2 = absl::StrCat(s1, s2);
-// tmp_1.c_str() and tmp_2.c_str() are safe.
-// The following behavior is dangerously subtle:
-// If the compiler can see you’re storing a reference to a
-// temporary object’s internals, it will keep the whole
-// temporary object alive.
-// struct Person { string name; ... }
-// GeneratePerson() returns an object; GeneratePerson().name
-// is clearly a sub-object:
-const std::string& person_name = GeneratePerson().name; // safe
-// If the compiler can’t tell, you’re at risk.
-// class DiceSeries_DiceRoll { `const string&` nickname() ... }
-// GenerateDiceRoll() returns an object; the compiler can’t tell
-// if GenerateDiceRoll().nickname() is a subobject.
-// The following may store a dangling reference:
-const std::string& nickname = GenerateDiceRoll().nickname(); // BAD!
-
- -## Option 4: Design your functions so they don’t return objects??? - -Many functions follow this principle; but many don’t. Sometimes it really is -better to return an object than to require the caller to pass in a pointer to an -output parameter. Be aware of when the creation of temporaries can happen. -Anything that returns a pointer or reference to an object’s internals is -potentially a problem when operating on a temporary object. `c_str()` is the -most obvious culprit, but protobuf getters (mutable or otherwise) and getters in -general can be equally problematic. diff --git a/_posts/2022-11-16-totw-3.md b/_posts/2022-11-16-totw-3.md deleted file mode 100644 index 789654e4..00000000 --- a/_posts/2022-11-16-totw-3.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: "Tip of the Week #3: String Concatenation and operator+ vs. StrCat()" -layout: tips -sidenav: side-nav-tips.html -published: true -permalink: tips/3 -type: markdown -order: "003" ---- - -Originally posted as TotW #3 on May 11, 2012 - - - -Updated 2022-11-16 - -Quicklink: [abseil.io/tips/3](https://abseil.io/tips/3) - - -Users are often surprised when a reviewer says, "Don't use the string -concatenation operator, it's not that efficient." How can it be that -`string::operator+` is inefficient? Isn't it hard to get that wrong? - -It turns out, such inefficiency isn’t clear cut. These two snippets have close -to the same execution time, in practice: - -
-std::string foo = LongString1();
-std::string bar = LongString2();
-std::string foobar = foo + bar;
-
-std::string foo = LongString1();
-std::string bar = LongString2();
-std::string foobar = absl::StrCat(foo, bar);
-
- -However, the same is not true for these two snippets: - -
-std::string foo = LongString1();
-std::string bar = LongString2();
-std::string baz = LongString3();
-std::string foobarbaz = foo + bar + baz;
-
-std::string foo = LongString1();
-std::string bar = LongString2();
-std::string baz = LongString3();
-std::string foobarbaz = absl::StrCat(foo, bar, baz);
-
- -The reason these two cases differ can be understood when we pick apart what is -happening in the expression `foo + bar + baz`. Since there are no overloads for -three-argument operators in C++, this operation is necessarily going to make two -calls to `string::operator+`. And between those two calls, the operation will -construct (and store) a temporary string. So `std::string foobarbaz = foo + bar -+ baz` is really equivalent to: - -
-std::string temp = foo + bar;
-std::string foobarbaz = std::move(temp) + baz;
-
- -Specifically, note that the contents of `foo` and `bar` must be copied to a -temporary location before they are placed within `foobarbaz`. (For more on -`std::move`, see [Tip #77](/tips/77).) - -C++11 at least allows the second concatenation to happen without creating a new -string object: `std::move(temp) + baz` is equivalent to -`std::move(temp.append(baz))`. However, it's possible that the buffer initially -allocated for the temporary won't be large enough to hold the final string, in -which case a reallocation (and another copy) will be required. As a result, in -the worst case, chains of `n` string concatenations require O(n) reallocations. - -It is better instead to use `absl::StrCat()`, a nice helper function from -google3/third_party/absl/strings/str_cat.h that calculates the necessary string -length, reserves that size, and concatenates all of the input data into the -output - a well-optimized O(n). Similarly, for cases like: - -
-foobar += foo + bar + baz;
-
- -use `absl::StrAppend()`, which performs similar optimizations: - -
-absl::StrAppend(&foobar, foo, bar, baz);
-
- -In addition, `absl::StrCat()` and `absl::StrAppend()` operate on types other -than just string types: you can use `absl::StrCat`/`absl::StrAppend` to convert -`int32_t`, `uint32_t`, `int64_t`, `uint64_t`, `float`, `double`, `const char*`, -and `string_view`, like this: - -
-std::string foo = absl::StrCat("The year is ", year);
-