struct FOO{
int a;
int b;
int c;
};
volatile struct FOO foo;
int main(void)
{
foo.a = 10;
foo.b = 10;
foo.c = 10;
struct FOO test = foo;
return 0;
}
This won't compile, because
struct FOO test = foo;
generates an error:
error: binding reference of type 'const FOO&' to 'volatile FOO'
discards qualifiers
How can I copy a volatile struct into another struct in C++ (before C++11)?
Many people suggested to just delelte volatile, but I can't do that in that case, because I want to copy the current SPI-Reg setttings inside a µC and this is declared volatile by the manufacturer headers.
I want to copy those settings, because the manufactuerer also provides an Library to use the SPI for EnDat-Communication, and I don't have access to the source-code. Since I have to change the SPI-Reg-Settings during runtime I want to easyly get back to the library SPI-settings without calling the init_endat()-lib fkt again (it's unspecified what happens if i call it twice).
Could I possibly use memcopy() for that?
As suggested, this is a copy of the following question.
Why am I not provided with a default copy constructor from a volatile?
This is ill-formed because FOO has an implicit copy constructor defined as:
FOO(FOO const&);
And you write FOO test = foo; with foo of type volatile FOO, invoking:
FOO(volatile FOO const&);
But references-to-volatile to references-to-non-volatile implicit conversion is ill-formed.
From here, two solutions emerge:
don't make volatile to non-volatile conversions;
define a suited copy constructor or copy the object members "manually";
const_cast can remove the volatile qualifier, but this is undefined behavior to use that if your underlying object is effectively volatile.
Could I possibly use memcopy() for that?
No you cannot, memcpy is incompatible with volatile objects: thre is no overload of it which takes pointers-to-volatile, and there is nothing you can do without invoking undefined behavior.
So, as a conclusion, your best shot if you cannot add a constructor to FOO is to define:
FOO FOO_copy(FOO volatile const& other)
{
FOO result;
result.a = other.a;
result.b = other.b;
result.c = other.c;
return result;
}
Or with C++11's std::tie:
FOO FOO_copy(FOO volatile const& other)
{
FOO result;
std::tie(result.a, result.b, result.c) = std::tie(other.a, other.b, other.c);
return result;
}
To give another approach to an answer, to address why this doesn't make sense, rather than just where the C++ standard says this is invalid:
The whole point of volatile is that you have precise control over which variable gets accessed when. That means given volatile int i, j;, i = 1; j = 2; and j = 2; i = 1; do not do the same thing. The compiler cannot freely transform one into the other. The same applies to reads: given volatile int i, j; int x, y;, x = i; y = j; and y = j; x = i; do not do the same thing. The presence of volatile means the accesses must happen in exactly the order you specified.
Now, in your example, what should struct FOO test = foo; do? You've never specified whether you want to first read foo.a, then foo.b, finally foo.c, or perhaps first read foo.c, then foo.b, finally foo.a, or perhaps some other order.
You can, if you wish, do this:
struct FOO test;
test.a = foo.a;
test.b = foo.b;
test.c = foo.c;
Here, you explicitly specify the order of the accesses to foo's fields, so you avoid the problem.
You haven't provided enough details about your problem to give a more precise assessment, but the solution to whatever problem you're trying to solve is almost certainly not to use volatile. "Volatile" means that the value can change from under your feet: the two typical good use cases are variables changed from within UNIX signal handlers and memory-mapped registers. Volatile is not enough for variables shared among threads, notably.
The reason you are getting this error is that your compiler is trying to find a FOO(volatile FOO&) copy constructor, which is never automatically generated.
Related
I have the following code which seems to work always (msvc, gcc and clang).
But I'm not sure if it is really legal. In my framework my classes may have "two constructors" - one normal C++ constructor which does simple member initialization and an additional member function "Ctor" which executes additional initialization code. It is used to allow for example calls to virtual functions. These calls are handled by a generic allocation/construction function - something like "make_shared".
The code:
#include <iostream>
class Foo
{
public:
constexpr Foo() : someConstField(){}
public:
inline void Ctor(int i)
{
//use Ctor as real constructor to allow for example calls to virtual functions
const_cast<int&>(this->someConstField) = i;
}
public:
const int someConstField;
};
int main()
{
//done by a generic allocation function
Foo f;
f.Ctor(12); //after this call someConstField is really const!
//
std::cout << f.someConstField;
}
Modifying const memory is undefined behaviour. Here that int has already been allocated in const memory by the default constructor.
Honestly I am not sure why you want to do this in the first place. If you want to be able to initalise Foo with an int just create an overloaded constructor:
...
constexpr Foo(int i) : someConstField{i} {}
This is completely legal, you are initalising the const memory when it is created and all is good.
If for some reason you want to have your object initalised in two stages (which without a factory function is not a good idea) then you cannot, and should not, use a const member variable. After all, if it could change after the object was created then it would no longer be const.
As a general rule of thumb you shouldn't have const member variables since it causes lots of problems with, for example, moving an object.
When I say "const memory" here, what I mean is const qualified memory by the rules of the language. So while the memory itself may or may not be writable at the machine level, it really doesn't matter since the compiler will do whatever it likes (generally it just ignores any writes to that memory but this is UB so it could do literally anything).
No.
It is undefined behaviour to modify a const value. The const_cast itself is fine, it's the modification that's the problem.
According to 7.1.6.1 in C++17 standard
Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const
object during its lifetime (3.8) results in undefined behavior.
And there is an example (similar to yours, except not for class member):
const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object
If your allocation function allocates raw memory, you can use placement new to construct an object at that memory location. With this you must remember to call the destructor of the object before freeing the allocation.
Small example using malloc:
class Foo
{
public:
constexpr Foo(int i) : someConstField(i){}
public:
const int someConstField;
};
int main()
{
void *raw_memory = std::malloc(sizeof(Foo));
Foo *foo = new (raw_memory) Foo{3}; // foo->someConstField == 3
// ...
foo->~Foo();
std::free(foo);
}
I suggest, that you use the constructor to avoid the const cast. You commented, that after your call of Ctor the value of someConstField will remain const. Just set it in the constructor and you will have no problems and your code becomes more readable.
#include <iostream>
class Foo
{
public:
constexpr Foo(int i) : someConstField(Ctor(i)){}
int Ctor(); // to be defined in the implementation
const int someConstField;
};
int main()
{
Foo f(12);
std::cout << f.someConstField;
}
Default Constructor, Copy Constructor and Destructor are very important and I understand why C++ implicitly defined them. Just think about function arguments that should be copied, local variables that should be destructed and objects that should be construct-able even if you don't say how to construct.
But why do we need the copy assignment operator implicitly defined? Is it really a must to be able to do a = b? It is not game changing, right? Any strong reason I don't know?
... why do we need the copy assignment operator?
Simply, to support assignment semantics. These are not the same as copy construction semantics.
Foo f1;
Foo f2(f1); // copy...
Foo f3;
f3 = f1; // assignment...
They are similar, and often implemented in terms of one another, but not the same.
Why would they all be implicitly defined?
To support and mimic the C-style value semantics. So that user defined types can support the same semantics as the built in types.
Side note; IIRC, there has been some deprecation of rules here with the onset of move semantics...
I believe it comes from one of the properties/capabilities of C++ which is being able to compile the native C code.
In C you are able to assign one struct variable to another e.g.
typedef struct foo_s
{
int field1;
int field2;
} foo_t;
int main ()
{
foo_t a, b;
a.field1 = 1;
a.field2 = 2;
b = a;
return 0;
}
So you should be able to compile this code as C++ thus you must have a default assignment operator.
If you copy-construct an object, you are able to set const members. Imagine you already have an object and then want to do an assignment. This would violate the constness of the members.
To clarify this a bit - because this short text seemed to be not sufficient for the most people - here some code:
struct C {
const int i;
C(int i) :i(i) {};
};
int main(void) {
C a(5), b(7);
a = b; // compiler error
C c(a); // no error
return 0;
}
So you need the assignment operator, because it has different semantics.
It is implicitly defined - if possible - because assignment should be defined by default whenever it is possible. Note, that in most cases your assignment operator is actually not implicitly defined. The above code is just one example, but there are many other cases: if you have a user declared move constructor for instance, then the copy assignment operator is not implicitly defined.
I just came across this code fragment, but I do not understand how it compiles:
class temp {
int value1;
mutable int value2;
public:
void fun(int val) const
{
((temp*) this)->value1 = 10;
value2 = 10;
}
};
What is the meaning of this line
((temp*) this)->value1 = 10;
value1 is getting assigned to 10, without any error. But value1 is not mutable. How does this compile?
When a member variable does not have the mutable qualifier, you cannot modify it when an object is const.
When a member variable has the mutable qualifier, you can modify it even when an object is const.
Simple example:
struct Foo
{
int var1;
mutable int var2;
};
const Foo f{};
f.var1 = 10; // Not OK
f.var2 = 20; // OK
When you have:
void fun(int val) const
{
((temp*) this)->value1 = 10;
value2 = 10;
}
you are bypassing the const-ness of the object and changing it in a way that you are not supposed to. This is subject to undefined behavior.
As far as the compiler is concerned, that code is equivalent to:
void fun(int val) const
{
temp* ptr = (temp*)this
// The compiler does not know how you got ptr.
// It is able to modify value1 through ptr since ptr
// points to a non-const object.
ptr->value1 = 10;
value2 = 10;
}
The line
((temp*) this)->value1 = 10;
is said to be "casting away const-ness". It basically tells the compiler: Take the this pointer (which has the type temp const* because we are in a const member function of temp), and pretend it were of type temp* (the subexpression (temp*)this). Then it instructs the compiler to dereference this pointer of type temp* to modify one of its members.
Casting away const-ness was how mutable data members were implemented before C++ offered the mutable keyword.
As you might have guessed, this is bad practice. It is bad practice, because it could just as well have been expressed with the mutable modifier. And it is bad practice because it uses the big gun of a C-style cast where a C++ const_cast<> would have sufficed.
The best way to learn is to start making it a trivial case and see how it goes.
a) if you comment out (*temp) and make it something like
this->value1 = 10;
error: assignment of data-member ‘temp::value1’ in read-only structure
or
b) if you comment out mutable keyword, you'll get the same error
error: assignment of data-member ‘temp::value2’ in read-only
structure
and if you read above R Sahu provided the right answer about mutable keyword.
If you are confused why can't we modify value with the normal way, remember the function is const and const is a contract that promises we are not supposed to modify or assign any values here (but mutable). so it is basically showing two techniques or hacks to break promise :-)
Consider this code:
struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
No compiler complains about it, even Clang. Why q() = ... line is correct?
No, the return value of a function is an l-value if and only if it is a reference (C++03). (5.2.2 [expr.call] / 10)
If the type returned were a basic type then this would be a compile error. (5.17 [expr.ass] / 1)
The reason that this works is that you are allowed to call member functions (even non-const member functions) on r-values of class type and the assignment of foo is an implementation defined member function: foo& foo::operator=(const foo&). The restrictions for operators in clause 5 only apply to built-in operators, (5 [expr] / 3), if overload resolution selects an overloaded function call for an operator then the restrictions for that function call apply instead.
This is why it is sometimes recommended to return objects of class type as const objects (e.g. const foo q();), however this can have a negative impact in C++0x where it can inhibit move semantics from working as they should.
Because structs can be assigned to, and your q() returns a copy of struct foo so its assigning the returned struct to the value provided.
This doesn't really do anything in this case thought because the struct falls out of scope afterwards and you don't keep a reference to it in the first place so you couldn't do anything with it anyway (in this specific code).
This makes more sense (though still not really a "best practice")
struct foo
{
int a;
};
foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }
int main()
{
foo i;
i.a = 5;
//sets the contents of the newly created foo
//to the contents of your i variable
(*(q())) = i;
}
One interesting application of this:
void f(const std::string& x);
std::string g() { return "<tag>"; }
...
f(g() += "</tag>");
Here, g() += modifies the temporary, which may be faster that creating an additional temporary with + because the heap allocated for g()'s return value may already have enough spare capacity to accommodate </tag>.
See it run at ideone.com with GCC / C++11.
Now, which computing novice said something about optimisations and evil...? ;-].
On top of other good answers, I'd like to point out that std::tie works on top of this mechanism for unpacking data from another function. See here. So it's not error-prone per se, just keep in mind that it could be a useful design pattern
I've found recently that most of the errors in my C++ programs are of
a form like the following example:
#include <iostream>
class Z
{
public:
Z(int n) : n(n) {}
int n;
};
class Y
{
public:
Y(const Z& z) : z(z) {}
const Z& z;
};
class X
{
public:
X(const Y& y) : y(y) {}
Y y;
};
class Big
{
public:
Big()
{
for (int i = 0; i < 1000; ++i) { a[i] = i + 1000; }
}
int a[1000];
};
X get_x() { return X(Y(Z(123))); }
int main()
{
X x = get_x();
Big b;
std::cout << x.y.z.n << std::endl;
}
OUTPUT: 1000
I would expect this program to output 123 (the value of x.y.z.n set in
get_x()) but the creation of "Big b" overwrites the temporary Z. As a
result, the reference to the temporary Z in the object Y is now
overwritten with Big b, and hence the output is not what I would
expect.
When I compiled this program with gcc 4.5 with the option "-Wall", it
gave no warning.
The fix is obviously to remove the reference from the member Z in the
class Y. However, often class Y is part of a library which I have not
developed (boost::fusion most recently), and in addition the situation
is much more complicated than this example I've given.
This there some sort of option to gcc, or any additional software that
would allow me to detect such issues preferably at compile time, but
even runtime would be better than nothing?
Thanks,
Clinton
I submitted such cases on the clang-dev mailing list a few months ago, but no one had the time to work on it back then (and neither did I, unfortunately).
Argyrios Kyrtzidis is currently working on it though, and here is his last update on the matter (30 Nov 23h04 GMT):
I reverted the previous commit, much
better fix in
http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20101129/036875.html.
e.g. for
struct S { int x; };
int &get_ref() { S s; S &s2 = s; int &x2 = s2.x; return x2; }
we get
t3.cpp:9:10: warning: reference to stack memory associated with local variable 's' returned
return x2;
^~
t3.cpp:8:8: note: binding reference variable 'x2' here
int &x2 = s2.x;
^ ~~
t3.cpp:7:6: note: binding reference variable 's2' here
S &s2 = s;
^ ~
1 warning generated.
The previous attempt failed the self-hosting test, so I hope this attempt will pass. I'm pretty glad Argyrios is looking into it anyway :)
It isn't perfect yet, admittedly, as it's quite a complicated problem to tackle (reminds me of pointer aliasing in a way), but this is nonetheless a great step in the right direction.
Could you test your code against this version of Clang ? I'm pretty sure Argyrios would appreciate the feedback (whether it is detected or not).
[Edited third bullet to demonstrate a technique that may help]
This is the rabbit hole you go down when a language permits passing arguments by value or reference with the same caller syntax. You have the following options:
Change the arguments to non-const references. A temporary value will not match a non-const reference type.
Drop the references altogether in cases where this is a possibility. If your const references don't indicate logically shared state between caller and callee (if they did this problem wouldn't occur very frequently), they were probably inserted in an attempt to avoid naive copying of complex types. Modern compilers have advanced copy ellision optimizations that make pass-by-value as efficient as pass-by-reference in most cases; see http://cpp-next.com/archive/2009/08/want-speed-pass-by-value for a great explanation. Copy ellision clearly won't be performed if you're passing the values on to external library functions that might modify the temporaries, but if that were the case then you're either not passing them in as const references or deliberately casting away the const-ness in the original version. This is my preferred solution as it lets the compiler worry about copy optimization and frees me to worry about other sources of error in the code.
If your compiler supports rvalue references, use them. If you can at least edit the parameter types of the functions where you worry about this problem, you can define a wrapper metaclass like so:
template < typename T > class need_ref {
T & ref_;
public:
need_ref(T &&x) { /* nothing */ }
need_ref(T &x) : ref_(x) { /* nothing */ }
operator T & () { return ref_; }
};
and then replace arguments of type T& with arguments of type need_ref. For example, if you define the following
class user {
int &z;
public:
user(need_ref< int> arg) : z(arg) { /* nothing */ }
};
then you can safely initalize an object of type user with code of the form "int a = 1, b = 2; user ua(a);", but if you attempt to initialize as "user sum(a+b)" or "user five(5)" your compiler should generate an uninitialized reference error inside the first version of the need_ref() constructor. The technique is obviously not limited to constructors, and imposes no runtime overhead.
The problem here is the code
Y(const Z& z) : z(z) {}
as the member 'z' is initialized with a reference to the formal parameter 'z'. Once the constructor returns the reference refers to an object which is no longer valid.
I don't think the compiler will or can in many cases detect such logical flaws. The fix then IMO is obviously to be aware of such classes and use them in a manner appropriate to their design. This should really be documented by the library vendor.
BTW, it is better to name the member 'Y::z' as 'Y::mz' if possible. The expression 'z(z)' is not very appealing