C++ - Why compiler doesn't allow to assign volatile variable [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 28 days ago.
Improve this question
What is the reason that the compiler doesn't autogenerate the volatile assignment operator, thus preventing the assignment?
A minimal example:
struct A{};
A a;
volatile A b;
b = a;

I assume you mean why when you create a class
class C {
// assignment operator auto generated
};
The assignment operator you get is
C& operator=(C const&) = default;
and not
C volatile& operator=(C volatile const&) volatile = default;
So a volatile glvalue cannot be on either side.
The reason is likely cost related. Volatile objects inhibit certain optimizations, and the qualifier sticks to sub-objects (both under pain of const_cast). They are also very rare in the wild, like really, practically no one ever declares volatile class objects. If C++ generated a volatile assignment operator by default, all code will need to pay a cost by default, even though they don't use volatile objects. But C++ is designed with the opposing philosophy, we don't pay for what we don't use.
If you are dealing with a library that necessitates the creation of volatile objects, and it breaks on this, then it is poorly designed. But honestly, it's far more likely the library never banked on having its objects declared volatile, and so perhaps it is you who should reconsider doing so.

Related

Rule "A user-defined but do-nothing destructor is also a non-trivial destructor" is too strict? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
class Base
{
public:
~Base() {}
private:
int val;
};
Base base; // a global variable
Look, the destructor does nothing, just same as the default destructor provided by c++ complier. But the destructor is still also a non-trivial destructor accroding to the post What is a non-trivial destructor in C++?
I know, each RULE from the standard must be strict.
But, by the upper codes I pasted, the user-defined destructor does nothing really! Why it is also non-trivial? I don't understand....
Is there any magic I don't konw?
Having the rule absolutely prohibit a definition gives a meaning to providing an empty one: it specifies that its instances must not be forgotten in an array that provides their storage. What the destructor does, if anything, can be considered an implementation detail that might change in future versions. It also avoids a change in meaning based on whether the “empty” destructor is defined in the class definition; if it isn’t, it can even be binary-compatible to change it to do something.

What is semantics? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
So there are copy semantics, move semantics and maybe more semantics that I don't know of. I have read articles about both but I still do not really get have a good definition of "semantics". As the name suggests, move semantics have something to do with moving things but why is it called move semantics?
The more clear version: What is the meaning of semantics in the context of programming? Example: Move and copy semantics.
Semantics basically means "the meaning of".
It may help to look at a more familiar case to explain the term.
Consider:
int a = 3;
int b = 5;
int c = a + b;
The value of a + b is 8 because the semantics of the + operator is to take the numerical sum of its operands.
Now consider this:
std::string a = "hello";
std::string b = "world";
std::string c = a + b;
The value of a + b is "helloworld" because the semantics of the + operator is to concatenate its operands.
The + operator, when used with std::string is said to have different semantics from when it is used with numerical types.
It has a different meaning.
Now consider copy and move semantics:
std::string a = "hello";
std::string b;
b = a; // b receives a copy of a's value
b = std::string("hello"); // the temporary value is moved into b
We have the same operator = which has a different meaning in different situations. Again we say is has different semantics.
The first case has copy semantics and the second case has move semantics.
The word semantics is used to describe an underlying meaning of something.
You can say that an operation has the move semantics when it transfers an object state from one object to another. In reality of course what happens is some pointers are probably copied over and that's it, but semantically your object has been moved.
Another example is the ownership transfer, when the most important thing that is moved is the responsibility (i.e. the promise to release some resource). In that case from the computational point of view pretty much nothing happens, but semantically the ownership is transferred.
The same goes for copy semantics: you can say that passing an object to a function has copy semantics i.e. your object would be duplicated and the function will get a standalone copy with its own lifetime.
Another side of the coin is the syntax which is how you describe what you want following the rules of the language.
C++ has really flexible syntax - overloading operators, user-defined conversions, macros and what not, so almost any desirable semantics can be attached to any particular syntax.
Semantics is about the meaning of something. move-semantic is about the meaning of moving objects. Specifically, in this context, it tells you what it means to move something in C++.
The semantic of moving is all about everything that is involved during a move operation.
read move-semantic as: what does it mean, what are the implications (and how do you achieve it ) of moving an object in a C++ program?
The following is a good answer that might help: What are move semantics?

Is there a good rule for using 'const' in classes and operator overloads in C++? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 6 years ago.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Improve this question
I have a piece of code like this:
class EducationalCentre
{
string _centreName;
vector<Course> _courses; // courses offered by the Centre
Collection<Course*, Student*, 150> _applicants;
public:
EducationalCentre(string name="<name>")
{
_centreName = name;
}
EducationalCentre(const EducationalCentre& obj)
:_courses(obj._courses), _applicants(obj._applicants)
{
_centreName = obj._centreName;
}
};
Now, in this part _applicants(obj._applicants) copy construction header, there's a squiggly red line around (obj, hovering it the error says something about type incompatibility (const being mentioned).
Since I don't want to change anything at this stage (this is a part of exam test) - I would like to know why is that happening.
I tried removing the const from EducationalCentre(const EducationalCentre& obj) and that indeed solves the problem but.. As I said, I would rather learn about what causes this instead of removing it.
Rule for using const is to use it whenever you can :)
Of course, like with all best practices there are exceptions, but in general you should always strive to make non-static methods const if they don't mutate the state of the object.
The reason for the problem you get is that Collection copy constructor takes a non-const reference to the instance it uses as a source object.
Copy constructor can take const or non-const reference as its argument but, IMO, non-const should only be used when you have no choice, which is rarely. Creating an object based on another object should not change the source object, thus it should be marked as const.
As I noted in the comment, the class being generic has nothing to do with copy ctor taking const reference. Indeed, if you take a look at e.g. std::vector you will see that it has a copy constructor which takes a const reference. Probably some of methods you use in Collection copy constructor on your argument is non-const and that is why you can't make argument const. The solution is to make the offending method const, too.
This brings us to an important point: constness is viral. If you mark a method const, all other method it calls on itself must also be const. Same for calling methods on const objects - you can only call const methods. If you don't do it from the beginning, you may end up in situation where making one method const results in changing a whole chain of other methods, so it is easier to give up.
Why constness is good: most bugs are caused by mutating application state in unexpected ways - just ask functional programming fans who rave about immutability :). A const method can't change the state of the object, so it eliminates the possibility of unexpected changes: e.g. if an exception is thrown in the middle of a const method, you can be sure that the object is not in some half-modified state which invalidates class invariants.
Now, C++ is not only an object oriented language, so you can change the application state in other ways, and also you can misuse mutable and const_cast to trick the compiler, but using const helps a lot in writing correct software and lowering the debugging efforts.

Move a variable and operate on it [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Is the following code safe?
struct Foo {
Foo bar() { return *this; }
} foo;
foo = std::move(foo).bar(); // is this safe?
I'm wondering if calling methods on an rvalue is safe.
In general, calling a function on an rvalue is no more or less safe than calling it on an lvalue.
As for your specific code, no movement actually happens. std::move(foo) converts it into an rvalue, which is irrelevant to the call to Foo::bar since it doesn't care whether this is an lvalue or an rvalue. bar will return a copy of foo, which will then be copied back into foo.
The same thing would have happened if you hadn't used std::move at all. std::move doesn't actually move anything; it simply converts it into an rvalue which can participate in a move operation.
Your real question is this: for any type T which is moveable, is this legal:
T t;
t = T(std::move(t));
The answer is... maybe. The state of a moved-from object is exactly what the writer of T chooses for it to be. For most standard library types, it will be "valid-but-unspecified". This means that you can use functions that don't require preconditions, that will work regardless of the current state.
Move assignment is usually such a function, so that will generally work. Will it work for all types? There is nothing which guarantees that it will. It depends on how move support is implemented for each type. Some user-defined types can't achieve even a "valid-but-unspecified" state, which means the only thing you're allowed to do with a moved-from object is destroy it.
It all depends on how users choose to work. However, I would say that a type for which t = T(std::move(t)) does not work (that is, yields undefined behavior) would be a very ill-behaved type.
Not super safe, it is sometimes hard to break down, if it's just for a simple program/game it should be fine, I would recommend that you use a more secure code for a big program :)
Overall it's not going to be too bad if it breaks.
What I mean by super safe is that it can't handle a break, if you decide to use a function of a standard way of doing it (e.g: using Struct like you have)
Sorry I can't supply as much information as I can, I'm newish to struct
if anyone wants to edit my answer they can.
Thanks,
~Coolq

Object doesn't get constructed [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I've noticed this weird behaviour/bug where a class method is called before the actual object is initialized. I have a wrapper object, which has operator->() method. Now, when I'm passing the object to another object as constructor parameter in a constructor using the operator->() method, the actual wrapper object doesn't get constructed, but rather just runs the operator->() method.
As the actual code sample is pretty complicated and depends on many other things, I'll just show C++ code snippet which may not compile properly:
template<typename T>
class wrapper_object_type
{
public:
wrapper_object_type() {/*does not run*/}
T* operator->() {/*does run*/}
};
class bad_behaviour
{
public:
bad_behaviour() : another_object(wrapper_object->t_object)
{/*crashes(0xccc access violation*/}
};
So is there something defined in the standard that may allow such behaviour? Or more accurately, are there some implicit constructions etc. which could bypass the default construction?
Probably you use wrapper_object before it gets initialized. Member variables are constructed in the same order in which they are declared in the class, so make sure wrapper_object is declared before another_object.
(Assuming wrapper_object and another_object are members variables of bad_behaviour, but without a more reasonable code sample it's hard to say.)
Well I did it the hardway; I switched the objects from stack to heap and initialized them explicitly via new keyword rather than in initializer list. As I thought, that didn't reproduce the weird behaviour, so it worked as intended. What I'm thinking now, is that it may be actually a compiler bug, since the way I did it via initializer list is analog to how I fixed the problem. Only thing that changed was the fact that I didn't allocate them in heap before.
I also tried to provide working code which reproduces the bug, but the bug wasn't shown there. It may be because the actual code where the bug was noticed, relies quite heavily to template types and wrapper objects. As it works now when the objects are allocated in heap, the bug isn't in the code but rather in the compiler.