I'm working on a c++ project for the university and I get problems with an uninitialized pointer in the following code :
#include <iostream>
using namespace std;
struct t_coord {
double valeur;
int indice;
t_coord *suiv;
};
struct t_vecteur {
int dimension;
double defaut;
t_coord *tete;
};
void initialiser (t_vecteur tv, int dimension, double defaut) {
tv.dimension = dimension;
tv.defaut = defaut;
tv.tete = nullptr;
}
int main () {
t_vecteur tv;
initialiser(tv, 5, 3.14);
return 0;
}
Is there anyway to override c4700 error in VisualStudio so I can use my initialization function "initialiser()" ? The final compilation will be done on GNU which does not take in account uninitialized variables and it is specified in the project that I have to create a function to initialize my t_vecteur.
Thanks in advance
The struct t_vecteur is an aggregate, and as such the instance tv is not initialized (dimension, defaut and tete, being primitive data types, contain indeterminate data).
Then you pass it by-value to the function initialiser, which reads from tv when making a copy, which invokes undefined behavior.
The relevant phrase of the standard is in [dcl.init]/12:
When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced
If an indeterminate value is produced by an evaluation, the behavior is undefined
To fix it (and the C4700 uninitialized variable warning), pass tv to initialiser by-reference.
void initialiser (t_vecteur& tv, int dimension, double defaut) {
Passing by-reference is not reading from tv, hence doing so is not UB anymore.
Related
The following C++ code compiles with no errors or warnings, but for some reason when I print out the contents of foo.arr I just get junk values. It looks like the array member is not being properly initialized.
template<int n> class C{
public:
const uint8_t (&arr)[n];
const int length = n;
C(const uint8_t (&arr_arg)[n]):arr(arr_arg)
{}
};
int main() {
C<5> foo{{1,2,3,4,5}};
for(int i =0;i<foo.length;i++){
printf("foo.arr[%d]=%2x\r\n",i,foo.arr[i]);
};
}
But if I write it like this, foo.arr is correctly initialized when I print out the results.
int main() {
const uint8_t x[]{1,2,3,4,5};
C<5> foo{x};
for(int i =0;i<foo.length;i++){
printf("foo.arr[%d]=%2x\r\n",i,foo.arr[i]);
};
}
Why does the second case work, but the first one doesn't?
One would think that the compiler would create a block of five bytes for the constant data {1,2,3,4,5} and then the initializer for foo would point foo.arr to that block of bytes. It seems that whatever foo.arr is pointing either not where that data is, or else that data doesn't exist any more by the time I print it out (possibly overwritten).
C<5> foo{{1,2,3,4,5}};
The constructor's parameter is a reference to a temporary object that gets destroyed after the constructor call finishes. All subsequent reference to this object results in undefined behavior.
C<5> foo{x};
Here, the constructor's parameter is a reference to an object that remains in scope and continues to exist as long as it is subsequently referenced and used.
It seems that ... data doesn't exist any more by the time I print it out (possibly overwritten).
That is, indeed, what's happening.
In the below code the variable a is passed to a constructor by reference, received by the parameter x. Then x is passed as a reference to an attribute. The attribute is then initialized with value 3. The program outputs the value 3 when running.
MY QUESTION
Shouldn't the program crash or show 2 because after the constructor is called
x should go out of scope and be released and its address should be freed right. and trying to write to it should give a memory access violation. However in this case the x is still in program control holding the address of 'a'
Is this valid c++ behavior or am i missing something?
#include <iostream>
#include <conio.h>
using namespace std;
class myclass {
public:
int& attribute;
myclass(int& x):attribute(x) {
}
void func() {
attribute = 3;
}
};
int main() {
int a = 2;
myclass obj(a);
obj.func();
std::cout << a;
_getch();
}
No this program is fine. attribute is a reference to a. The fact that x has gone out of scope is neither here nor there.
If you changed your code to
myclass(int x):attribute(x)
then that would be a problem.
The behavior of the program line by line
variable "a" is initialized with value 2
int a = 2;
Initialize obj with the variable a
myclass obj(a);
First x becomes the reference to a, then attribute becomes the reference to x. Consequently, attribute becomes the reference to a, which has the value 2 at the moment.
myclass(int& x):attribute(x) {}
Call func() of obj
obj.func();
attribute is the reference to a.
Both "attribute" and "a" are changed to 3. Consider them as the same,
single variable, just with difference alias.
That means, at this moment, attribute and a refers to the same variable,
and can be used interchangeably.
void func() {
attribute = 3;
}
#include <iostream>
using namespace std;
class A{
public:
int data[3];
private:
int cnt;
public:
void put(int v){data[cnt++]=v;}
int take(){int c=cnt;cnt=0;return c;}
};
int main() {
A a;
a.take();
a.put(a.take());
a.put(1);
cout<<a.data[0];
return 0;
}
I understand most of this code, but I got confused by the function a.take(). In the main function, we firstly create an object a. Then we run a.take(). In this function, we first let c = cnt and then cnt is assigned a value of 0.
Why isn't there an error when c is assigned the value of cnt which has not have a value yet.
It is total understandable for me if this function is written as
int take(){cnt=0;c = cnt;return c;}
The author of this code is of the belief that using the initial call to take() to establish the cnt member value of 0 is standard-compliant; they're wrong (at least through C++14, I've not checked C++17)
Per the standard,
8.5 Initializers [dcl.init]
If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or
dynamic storage duration is obtained, the object has an indeterminate
value, and if no initialization is performed for the object, that
object retains an indeterminate value until that value is replaced
(5.18). [Note: Objects with static or thread storage duration are
zero-initialized, see 3.6.2. — end note ] If an indeterminate value is
produced by an evaluation, the behavior is undefined except in the
following cases:
None of the exceptions apply to you, so I didn't bother showing them, but you can look them up for confirmation.
The proper way to do this is to establish a determine value for cnt before first use (such as a member initialization list), at which point the worthless take() call can then be removed. In other words,
#include <iostream>
using namespace std;
class A{
public:
int data[3];
private:
int cnt;
public:
A() : cnt(0) {} // HERE
void put(int v){data[cnt++]=v;}
int take(){int c=cnt;cnt=0;return c;}
};
int main()
{
A a;
a.put(a.take());
a.put(1);
cout<<a.data[0];
return 0;
}
Let's walk through main():
A a;
At this step, you created an object a of type A.
What is in a?
(1) a public data member called data, which is an array of int.
(2) a private data member called cnt, which is an int.
Note that at this step, the object a already has these two data members.
What their values are is another matter.
(3) public function members take() and put().
a.take()
Now you have created a, you can use it.
a.take() calls the public member function of take() of a.
In the body of take()
int c=cnt;cnt=0;return c;
c is initialzed with the value of the private data member cnt of a, before it is returned.
So it boils down to the question: What is the value of cnt at this point?
Your question:
Why isn't there an error when c is assigned the value of cnt which has not have a value yet.
Your wording is not accurate. cnt does have a value. This value is undefined, however, in this case. That is, it could be anything. It could be 0, or 42, or -123.
The details:
Since you do not provide a default constructor A() for class A, the compiler would generate a synthesized default constructor for A, which is used to construct a.
Since you do not provide an in-class initializer for cnt (like int cnt = 0;), the default constructor will default initialize cnt.
Since cnt is an int, which is a built-in type, the default initialization rule for a built-in type says, variables of built-in type defined inside a function are uninitialized. The value of an uninitialized variable of built-in type is undefined.
Since a is defined in function main(), cnt has an undefined value.
As cnt is a member variable (non-global), it's value is un-initialized, which means it could be whatever was in that memory location before. It's not an error to use it but the value it will read is effectively garbage.
As a side note, global and static variables are initialized to 0.
I am new to c++ and I want to learn best practice of c++. I got one question, does the modern c++ compiler will auto assign default value for an uninitialized variable? If yes, does it mean that we do not need to assign default value to a variable or it depends on system?
Thank you for your help and clarification.
Only static and global data is always initialised...
int w; // will be 0
static int x; // will be 0
void f() { static int x; /* will be 0 the first time this scope's entered */ }
struct S
{
int n_;
};
S s_; // s_.n_ will be 0 as s_ is global
int main()
{
S s; // s.n_ will be uninitialised
// undefined behaviour to read before setting
}
For any other variables they must have - at some level in the code - explicit initialisation before they're read from. That might not be visible at the point a variable is declared though - it could be in a default constructor or an assignment. You can also cause initialisation like this:
int x{}; // will be 0
int* p = new int{}; // *p will be 0
Default initialization is performed in three situations:
1) when a variable with automatic, static, or thread-local storage duration is declared with no initializer.
2) when an object with dynamic storage duration is created by a new-expression with no initializer or when an object is created by a new-expression with the initializer consisting of an empty pair of parentheses (until C++03).
3) when a base class or a non-static data member is not mentioned in a constructor initializer list and that constructor is called.
More information here:
http://en.cppreference.com/w/cpp/language/default_initialization
With regard to what the compiler will do I think its more of the inverse, for example:
int x; // still must be inited, will contain random data
if (some_func())
{
// some devs will do this for "performance" - i.e don't assign a value to x
x = 2;
}
But if you write:
int x = 0;
if (some_func())
{
x = 2;
}
The compiler will optimize this to:
int x;
if (some_func())
{
x = 2; // Yes this code is actually the first example again :)
}
Assuming x is not used else where in the function.
Consider the following code:
int * p;
void Set()
{
int i = 7;
p = & i; // potentially disastrous
}
I know that pointing to a value that may be overwritten is bad but I recall reading that there was a way to prevent a value such as i from being lost when declared and then pointed to in this way. I've scoured my text book but have had trouble finding the exact text elaborating on this and am starting to think I may have even imagined it. Is there a way of safely pointing to a temporary value declared inside of a function? A way of making the temporary value i no longer temporary?
Thanks for all your help in advance!
I recall reading that there was a way to prevent a value such as i from being lost when declared and then pointed to in this way
The closest thing to what you mention (if I understood your sentence correctly) is the rule which allows prolonging the lifetime of a temporary when bound to a reference (§ 12.2/5 of the C++11 Standard):
struct X { int x = 0; };
X foo() { return X(); }
int main()
{
X const& x = foo(); // The lifetime of the object bound to x is prolonged
x.x = 42; // This is OK
}
However, there is no such rule for pointers nor for objects that are not temporaries.
A way of making the temporary value i no longer temporary?
In your example, i is not a temporary: it is an object with automatic storage duration. A temporary is an object whose life-time (usually) terminates at the end of the full expression that creates it (with the exception mentioned above and a few more listed in § 12.2/4-5).
taking const ref to an temporary extends liifetime of this temporary up to the end of scope of this const reference, however in your example you are not taking address of temporary but local automatic object i.
so to extends lifetime of temporary do simply:
const int& iref=int(3);
int a= iref;
//..do stuff with iref, i.e:
printf("iref: %d\n", a);
output:
iref: 3
RUN SUCCESSFUL (total time: 46ms)
The value of i has to reside in memory somewhere. If you declare it inside a function, it is likely to be allocated on the stack and will be lost when the function returns. If you really need the value to always be constant like in your example, then what you need is to declare it outside the function as static const:
int * p;
static const int i = 7;
void Set()
{
p = & i;
}
If this is not what you need, maybe you can elaborate a bit on your very minimal example code so that we can better understand what you are trying to achieve.
you can use the static keyword.
#include <stdio.h>
int *p;
void set() {
static int x = 7;
p = &x;
}
int main(){
set();
printf("%d", *p);
}
correctly prints 7.
however, I would strongly discourage using such a piece of code in anything but a research on the static keyword and pointers.