class foo {
std::vector<int> datas;
public:
template <typename It>
foo(It x, It y) {
for(; x != y; ++x)
insert(*x);
}
void insert(int val) {
if(val == 5)
throw 99;
else
datas.push_back(val);
}
void print() const {
for(int x : datas)
std::cout << x << " ";
}
};
int main() {
std::vector<int> v{1, 2, 3, 5, 6, 7};
foo* f;
try {
f = new foo(std::begin(v), std::end(v));
}catch(int const& x) {
}
f->print();
}
I suppose that f wouldn't be constructed in this case; the exception thrown by the insert method is not handled in the body of foo constructor.
I got the following output on gcc 8.2.0 :
1 2 3 5 6 7
I suppose that f wouldn't be constructed in this case;
A foo instance would not be constructed in this case.
Furthermore, f would not have been assigned to, so its value would remain indeterminate.
Is this a right behavior?
Accessing an object by indirecting through an indeterminate pointer has undefined behaviour.
While the undefined nature has been discussed, I feel like it might be interesting to look into actual produced result and speculate why we see it.
While I have no proof, I believe it is an interesting consequence of compiler optimizations and code reasoning. We see that the output is 1 2 3 5 6 7, even though the code has a throw statement for element 5. How would this happen?
In my view, since we have f->print() outside of try block, compiler reasons that f is never uninitialized - so constructor never throws. Since constructor never throws, val == 5 is never true! Because of that, the branch is removed. And thus we have the result we do have.
Related
This question already has answers here:
C++: Life span of temporary arguments?
(4 answers)
Closed 7 months ago.
This question is a follow up to How come std::initializer_list is allowed to not specify size AND be stack allocated at the same time?
The short answer was that calling a function with brace-enclosed list foo({2, 3, 4, 5, 6}); conceptually creates a temporary array in the stackspace before the call and then passes the initializer list which (like string_view) just references this local temporary array (probably in registers):
int __tmp_arr[5] {2, 3, 4, 5, 6};
foo(std::initializer_list{arr, arr + 5});
Now consider the following case where I have nested initializer_lists of an object "ref". This ref object stores primitives types or an initializer_list recursively in a variant. My question now is: Is this undefined behaviour? It appears to work with my code, but does it hold up to the standard? My reason for doubting is that when the inner constructor calls for the nested brace-enclosed lists return, the temporary array which the initializer list is refering to could be invalidated because the stack pointer is reset (thus saving the initializer_list in the variant preserves an invalid object). Writing to subsequent memory would then overwrite values refered to by the initializer list. Am I wrong in believing that?
CompilerExplorer
#include <variant>
#include <string_view>
#include <type_traits>
#include <cstdio>
using val = std::variant<std::monostate, int, bool, std::string_view, std::initializer_list<struct ref>>;
struct ref
{
ref(bool);
ref(int);
ref(const char*);
ref(std::initializer_list<ref>);
val value_;
};
struct container
{
container(std::initializer_list<ref> init) {
printf("---------------------\n");
print_list(init);
}
void print_list(std::initializer_list<ref> list)
{
for (const ref& r : list) {
if (std::holds_alternative<std::monostate>(r.value_)) {
printf("int\n");
} else if (std::holds_alternative<int>(r.value_)) {
printf("int\n");
} else if (std::holds_alternative<bool>(r.value_)) {
printf("bool\n");
} else if (std::holds_alternative<std::string_view>(r.value_)) {
printf("string_view\n");
} else if (std::holds_alternative<std::initializer_list<ref>>(r.value_)) {
printf("initializer_list:\n");
print_list(std::get<std::initializer_list<ref>>(r.value_));
}
}
}
};
ref::ref(int init) : value_{init} { printf("%d stored\n", init); }
ref::ref(bool init) : value_{init} { printf("%s stored\n", init ? "true" : "false"); }
ref::ref(const char* init) : value_{std::string_view{init}} { printf("%s stored\n", init); }
ref::ref(std::initializer_list<ref> init) : value_{init} { printf("initializer_list stored\n", init); }
int main()
{
container some_container = { 1, true, 5, { {"itemA", 2}, {"itemB", true}}};
}
Output:
1 stored
true stored
5 stored
itemA stored
2 stored
initializer_list stored
itemB stored
true stored
initializer_list stored
initializer_list stored
---------------------
int
bool
int
initializer_list:
initializer_list:
string_view
int
initializer_list:
string_view
bool
First of all, copying a std::initializer_list does not copy the underlying objects. (cppreference)
and
container some_container = { 1, true, 5, { {"itemA", 2}, {"itemB", true}}};
actually compiles to something like
container some_container = { // initializer_list<ref>
ref{1},
ref{true},
rer{5},
ref{ // initializer_list<ref>
ref{ // initializer_list<ref>
ref{"itemA"},
ref{2}
},
ref{ // initializer_list<ref>
ref{"itemB"},
ref{true}
}
}
};
and all those object's lifetime* end at end of full expression (the ; here)
*including all initializer_list<ref>, their underlying array, and all the belonging ref objects, but not the one in the constructor (copy elision may apply though)
so
yes it's fine to use those object in the constructor.
those object are gone after the ; so you should not use the stored object (in initializer_list) anymore
godbolt example with noisy destructor and action after the construction
This question already has answers here:
return const reference vs temporary object
(3 answers)
Closed 10 months ago.
There is a simple program
#include <stdio.h>
int counter = 3;
const int& f() {
return counter++;
}
const int& g() {
return counter++;
}
const int& h(int w) {
counter = w;
return counter;
}
void main()
{
const int& x = f();
const int& y = g();
const int& z = g();
const int& t = h(123);
counter = 45678;
printf("%d %d %d %d", x, y, z, t);
}
Why its output is 5 5 5 45678? Especially, why x and y are 5? If they are still connected to the counter after initialization, why they are not 45679 or something like?
Because of post-incrementation that f and g do.
const int& f() {
return counter++;
}
const int& g() {
return counter++;
}
counter++ doesn't actually return the counter, but a temporary int object returned by operator++(int).
In C++, opreator++ has two forms.
Type& operator++(); //pre-increment
Type operator++(int); //post-increment
The int argument in the 2nd version is a dummy used to distinguish the calls, as you can't overload on return type alone
As you can see the post-increment returns by value, not reference, so you're returning a reference to a temporary variable!
You can see warning from GCC and Clang if you turn them on.
https://godbolt.org/z/f1fMP463a
So overall you invoke UB as the references you return are dangling. You ran into the worst case where it just seems to work.
Also, main must return int in C++.
Your program has undefined behaviour. The return values of f and g cease to exist at the end of the statements that call them, so x, y and z don't refer to anything after their declaration.
Just as an addition to the answers given so far: Why undefined behaviour?
Let's consider a hypothetical implementation of operator++:
template <typename T>
T& operator++(T& t) // pre-increment:
{
t = t + 1;
return t;
}
// should be clear so far...
template <typename T>
T operator++(T& t, int) // post-increment:
{
// t = t + 1; // cannot do now, how to return the old value then???
T b = t; // need to store the value in a backup copy first!
t = t + 1; // NOW we can
return t; // need to return the OLD value -> cannot return by reference either,
// it's a TEMPORARY ...
}
As you now use operator++, which itself returns a temporary, you return a reference to temporary that doesn't exist any more after after returning – undefined behaviour.
Why do you now see 5? Pure technically (still UB!): As f and g look identical they both use identical offsets to the stack's end on being called and as being called immediately one after another they both start at the same stack end – so they will store the temporary at the same stack address, which is where the reference gets bound to. Note that this finally contains the value before last increment, thus 5, not 6. h does not need any additional values on the stack, thus the value there won't get overwritten – just alike when doing the assignment, so the value is yet retained. You might have seen something totally different if for some reason h did use the stack itself...
#include <list>
#include <iostream>
#include <utility>
#include <conio.h>
std::list<int>&& asd()
{
std::list<int> a{ 4, 5, 6 };
return std::move( a );
}
int main()
{
std::list<int> a{ 1, 2, 3 };
std::list<int> &&b = std::move( a );
for( auto &iter : b )
{ std::cout<<iter<<' '; }
std::list<int> &&c{ asd() };
for( auto &iter : c )
{ std::cout<<iter<<' '; _getch(); }
}
this is what my program outputs:
1 2 3
4 3502376 454695192 3473720 4 3502376 454695192 3473720 4 3502376 454695192 3473720 4
std::list<int> a{ 4, 5, 6 };
This object is declared locally inside this function, so it gets destroyed when the function returns.
std::list<int>&& asd()
This function returns an rvalue reference. A reference to some unspecified object.
What happens here is that this "unspecified object" gets destroyed when this function returns, so the caller ends up holding a reference to a destroyed object.
return std::move( a );
The dirty little secret is that std::move() does not actually move anything. It never did, it never will. All that std::move() does is cast its parameter into an rvalue reference. Whether the object gets moved, or not, requires other dominoes to fall into place. std::move() merely provides one piece of the puzzle, but all other pieces of this puzzle must exist in order for an actual move to happen.
Here, those other pieces of the puzzle do not exist. Therefore, nothing gets moved. A reference to a destroyed object gets returned, and all subsequent use of the destroyed object results in undefined behavior.
I am new to cpp and I am trying out several things. This one I can't seem to figure out on my own.
#include <cstdio>
#include <stdexcept>
template <class E, class V>
struct Pair {
E first;
V second;
Pair(E fst, V snd) : first(fst), second(snd) {}
E getFirst() { return first; }
V getSecond() { return second; }
};
template <class t, unsigned dim>
struct vec {
t d[dim];
static constexpr int dimen = dim;
t &operator[](unsigned n) {
std::printf("dim: %d %d\n", dim, n);
if (n >= dim) {
std::printf("checking %d\n", n);
throw std::out_of_range("vector index is out of range");
}
return d[n];
};
};
int main() {
try {
Pair<int, vec<int, 2> *> test2(2, new vec<int, 2>{1, 2});
std::printf("%d\n", test2.getSecond()->dimen);
std::printf("before\n");
std::printf("%d\n", test2.getSecond()->d[2]); // it seems like the compiler kind of ignores this
} catch (std::out_of_range e) {
std::printf("Caught!!");
}
return 0;
}
Now, the line std::printf("%d\n", test2.getSecond()->d[2]); should ideally throw the out_of_range error, but it is not. My linter actually warns me that this is out of range also. I can compile and run the program and it returns some garbage 0 value.
My question is: why is either the error not being thrown or the error not being caught? I think the error is not being thrown because checking is not printed when I run it.
Because the throw code is never actually reached.
In this line here:
std::printf("%d\n", test2.getSecond()->d[2]);
getSection() returns a pointer to the vec object. When you then do ->d you are accessing the d array, within the vec object. Thus, when you add the [2] to the end, you are accessing the element at index 2 of the array, and are not calling operator[] of the vec object.
If you rewrite like this:
std::printf("%d\n", (*test2.getSecond())[2]);
Then the operator[] will be called on the vec object, and not its array. Note that you have to dereference the result of getSecond(). Alternatively, you can be more verbose:
std::printf("%d\n", test2.getSecond()->operator[](2));
Working example: https://godbolt.org/z/YWKzPz
Very good question!
The issue is that when you try to reference an item in an array via index, such as [2], you are actually referring to the size * 2 location. There is no built-in protection against it, but you can always check for \0 as that's where your arrays end. When you use arrays in C/C++, it is your job to make sure you are not outside of their location. It's generally a good idea to keep your array inside your structure/class and allow reaching its elements with setters and getters, which would handle the bounds and throw exceptions if those are violated.
I have the following problem I want to be solved. I started out with a large class P, which I wanted to split up. Therefore a part of the functionality was moved to a new class Q. However, I do not seem to be able to make these two communicate properly. To make this a bit more visual, I made this toy example:
#include <iostream>
class Q {
public:
int* x_ptr;
Q(){ } // Is there any way to not have to write default constructors?
Q(int* x_ptr){
x_ptr = x_ptr;
}
void say_x(){
std::cout << *x_ptr << std::endl;
}
void change_x(){
*x_ptr += 1;
}
};
class P {
public:
Q q;
int x;
P(int x){
x = x;
q = Q(&x);
}
};
int main(){
P my_p = P(10);
my_p.q.say_x();
my_p.q.change_x();
std::cout << my_p.x << std::endl;
}
I want the class Q to be responsible for changing P.x. To do this, I thought that passing a reference to P.x to Q when it's created would work. However, this results in a segmentation fault. Is there a way to make Q able to access and modify x? The reason for this is that I eventually want to have a number of classes Q1, Q2 etc, which are all responsible for different operations on P.x, where P.x will be a more complicated data type than a simple int.
Your problems arise from the fact that your are using the same variable names for both function arguments and class members. Although this is allowed, it is (IMHO), very bad practice. If you want to keep the names, then you will need to add an explicit this-> in the functions where you need to distinguish between the two, otherwise your argument names will 'shadow' the class members.
So, your Q constructor, keeping the name-clashes, would need to be:
Q(int* x_ptr) {
this->x_ptr = x_ptr;
}
and your P constructor would be:
P(int x) {
this->x = x;
q = Q(&(this->x));
}
However, with simple name-changes to the arguments, this is much clearer:
Q(int* arg_x_ptr) {
x_ptr = arg_x_ptr;
}
//...
P(int arg_x) {
x = arg_x;
q = Q(&x);
}
As it stands, in your code, the line q = Q(&x); in the P constructor passes the address of the temporary object given as the argument, which causes a memory error (segmentation fault) when you later try to modify it.
Note: On your comment about not having to define a default constructor for Q - you can remove this provided you give the 'required' parameter when you declare/instatiate the q member in P:
class P {
public:
Q q{ nullptr }; // BEWARE: You can NEVER use this object as it stands!
int x;
//...