For performance optimization, I would like to make use of the reference of a string rather than its value. Depending on the compilation options, I obtain different results. The behavior is a bit unclear to me, and I do not know the actual gcc
flag that causes that difference.
My code is
#include <string>
#include <iostream>
const std::string* test2(const std::string& in) {
// Here I want to make use of the pointer &in
// ...
// it's returned only for demonstration purposes...
return ∈
}
int main() {
const std::string* t1 = test2("text");
const std::string* t2 = test2("text");
// only for demonstration, the cout is printed....
std::cout<<"References are: "<<(t1==t2?"equivalent. ":"different. ")<<t1<<"\t"<<t2<<std::endl;
return 0;
}
There are three compilation options:
gcc main.cc -o main -lstdc++ -O0 -fPIC && ./main
gcc main.cc -o main -lstdc++ -O2 -fno-PIC && ./main
gcc main.cc -o main -lstdc++ -O2 -fPIC && ./main
The first two yield equivalent results ( References are: different.
), so the pointers are different, but the third one results in equivalent pointers ( References are: equivalent.
). Why does this happen, and which option do I have to add to the options -O2 -fPIC
such that the pointers become again different? Since this code is embedded into a larger framework, I cannot drop the options -O2
or -fPIC
.
Since I get the desired result with the option -O2
and also with -fPIC
, but a different behavior if both flags are used together, the exact behavior of these flags is unclear to me.
I tried with gcc4.8 and gcc8.3.
Both t1
and t2
are dangling pointers, they point to a temporary std::string
which is already destroyed. The temporary std::string
is constructed from the string literal during each call to test2("text")
and lives until the end of the full-expression (the ;
).
Their exact values depend on how the compiler (re-)uses stack space at a particular optimization level.
which option do I have to add to the options
-O2 -fPIC
such that the pointers become again different?
The code exhibits undefined behavior because it's illegal to compare invalid pointer values . Simply don't do this.
If we ignore the comparing part, then we end up with this version:
#include <string>
#include <iostream>
void test2(const std::string& in) {
std::cout << "Address of in: " << (void*)&in << std::endl;
}
int main() {
test2("text");
test2("text");
}
Now this code is free from UB, and it will print either the same address or different addresses, depending on how the compiler re-uses stack space between function calls. There is no way to control this, but it's no problem because keeping track of addresses of temporaries is a bad idea to begin with.
You can try using const char*
as the input argument instead, then no temporary will be created in a call test2("text")
. But here again, whether or not two instances of "text"
point to the same location is implementation-defined . Though GCC does coalesce identical string literals, so at least in GCC you should observe the behavior you're after.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.