why atomic does not work with auto varaible - c++

I am not sure what is wrong with following statements , its giving me compilation errors. Can we not use "auto" with atomic variables?
#include <iostream>
#include<future>
#include <atomic>
using namespace std;
int main()
{
atomic<int> value(10);
auto NewValue = value;
}
but if I replace "auto" with "int" , it works. Why?
int main()
{
atomic<int> value(10);
int NewValue = value;
}
Compilation error with "auto"
||=== Build: Debug in Hello (compiler: GNU GCC Compiler) ===|
F:\3d\C++CodeProject\Hello\main.cpp||In function 'int main()':|
F:\3d\C++CodeProject\Hello\main.cpp|11|error: use of deleted function
'std::atomic<int>::atomic(const std::atomic<int>&)'|
C:\Program Files
(x86)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\atomic|612|note:
declared here|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===|

auto matches the data type on the right-hand side of the assignment. In this statement:
auto NewValue = value;
value is a std::atomic<int>, so auto will deduce to std::atomic<int>, not to int like you are expecting.
IOW, this:
auto NewValue = value;
Is the same as this:
atomic<int> NewValue = value;
Which is copy initialization using a copy constructor, but std::atomic has a delete'd copy constructor, which is exactly what the error message says:
use of deleted function 'std::atomic<int>::atomic(const std::atomic<int>&)'
std::atomic has a conversion operator for T, which is why int NewValue = value; works.

Atomic variables are not copy constructible: http://en.cppreference.com/w/cpp/atomic/atomic/atomic (3)
This is what auto will attempt to do in this instance.
However, you can cast it down to an int, using the operator int conversion: http://en.cppreference.com/w/cpp/atomic/atomic/operator_T

Related

std::compare_exchange int with #define value

I want to use std::compare_exchange_strong for some std::atomic<int>
For compilation reasons (int &) I am forced to introduce int _OLD_VALUE = OLD_VALUE.
Is there a more elegant way to achieve this?
Here is my example
#include <atomic>
#include <stdio.h>
#define OLD_VALUE 16
#define NEW_VALUE 744
#define OTHER_VALUE 80
int main(int argc, char **argv)
{
std::atomic<int> i(OTHER_VALUE);
int _OLD_VALUE = OLD_VALUE;
bool status = i.compare_exchange_strong(_OLD_VALUE,NEW_VALUE);
// bool status = i.compare_exchange_strong( OLD_VALUE,NEW_VALUE);
if (status) { printf("good\n"); }
return 0;
}
And here is the compilation error when I use the commented version:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:11:65: error: cannot bind non-const lvalue reference of type ‘std::__atomic_base<int>::__int_type& {aka int&}’ to an rvalue of type ‘int’
bool status = i.compare_exchange_strong( OLD_VALUE,NEW_VALUE);
^
In file included from /usr/include/c++/7/atomic:41:0,
from main.cpp:1:
/usr/include/c++/7/bits/atomic_base.h:496:7: note: initializing argument 1 of ‘bool std::__atomic_base<_IntTp>::compare_exchange_strong(std::__atomic_base<_IntTp>::__int_type&, std::__atomic_base<_IntTp>::__int_type, std::memory_order) [with _ITp = int; std::__atomic_base<_IntTp>::__int_type = int; std::memory_order = std::memory_order]’
compare_exchange_strong(__int_type& __i1, __int_type __i2,
^~~~~~~~~~~~~~~~~~~~~~~
No. The reason being is that the previous value of the variable is exchanged so the expected value is overwritten if the compare mismatches.
To see what's going on under the hood, look at the GCC built-ins:
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
You will note there is a __atomic_exchange_n in the builtins for GCC (Linux) but that simply provides an exchange as opposed to a compare-and-swap. The Windows equivalent is InterlockedExchange : https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchange
For the sake of readability I would avoid using capitals in variable names and avoid leading underscores:
int oldValue = OLD_VALUE;
The simplest way (and I suppose the only way) to achieve this is to just write simple wrapper:
bool cas_strong(std::atomic<int>& a, int cmp, int exc) {
return a.compare_exchange_strong(cmp, exc);
}
compare_exchange_strong expects an int& to store the current value found in i. Here, you provide indirectly 16 (that is what your macro OLD_VALUE is replaced with at pre-processing), which is an integer compile-time constant, a.k.a. constexpr int&. This is not compatible with int&.
To provide an int&, you should better keep an int near your call of compare_exchange_strong:
std::atomic<int> i(OTHER_VALUE);
int old_value = OLD_VALUE;
bool status = i.compare_exchange_strong(old_value, NEW_VALUE);
if (status) { printf("good\n"); }
return 0;
Also, more generally, it is clearly more powerful if you used static constants instead of macros here.
More on this in this other question: What is the difference between a macro and a const in C++?
Don't use macros to define the values:
#include <atomic>
#include <stdio.h>
int OLD_VALUE 16
int NEW_VALUE 744
int OTHER_VALUE 80
int main(int argc, char **argv)
{
std::atomic<int> i(OTHER_VALUE);
bool status = i.compare_exchange_strong( OLD_VALUE,NEW_VALUE);
if (status) { printf("good\n"); }
return 0;
}

Error while compiling in gcc

I am doing a project for my class where the instructor had given us some code snippets and we were asked to modify it. The code compiles correctly in my class computer in Visual Studio but when I try to compile it with gcc it gives me an error.
The error I am getting is:
||=== Build: Debug in Project (compiler: GNU GCC Compiler) ===|
/home/nitin/Read.h|45|error: declaration of ‘std::vector<rv> rvs::rv’ [-fpermissive]|
/home/nitin/Read.h|35|error: changes meaning of ‘rv’ from ‘struct rv’ [-fpermissive]|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
The code from the error is snippet for this is:
struct rv
{
double val, prob;
rv(const double v, const double p): val(v), prob(p) {};
};
struct rvs
{
int row_n, col_n;
vector<rv> rv;
rvs(const int r=-2, const int c=-2): row_n(r), col_n(c) {};
};
Could you please let me know what the problem could be?
Your declarations violate the following rule
3.3.7 Class scope [basic.scope.class]
1 The following rules describe the scope of names declared in classes.
...
2) A name N used in a
class S shall refer to the same declaration in its context and when
re-evaluated in the completed scope of S. No diagnostic is required
for a violation of this rule.
At the point of vector declaration name rv refers to a type struct rv. But when reevaluated in the scope of complete class rvs it, refers to class member rvs::rv. Such inconsistency is an error in C++.
A similar error is illustrated by an example in the standard
enum { i = 1 };
class X {
char v[i]; // error: i refers to ::i
// but when reevaluated is X::i
...
enum { i = 2 };
};
As #Ben Voigt stated in the comment, if you explicitly resolve the conflict between rv as struct rv and rv as rvs::rv, the error will go away. You can do it by either using elaborate type specifier struct rv or by specifying scope explicitly ::rv.
Note that this is one of those errors which are not guaranteed/required to be caught by the compiler.
You have a type called rv and a member variable called rv. How is the compiler supposed to know which one you mean when you write rv?
Strictly this is invalid code, but Visual Studio seems to be willing to try to let you shoot yourself in the foot.

Code Blocks C++ Error expected primary expression before enum

I am self teaching myself in C++ so I just would like to ask for your forgiveness if my question is really basic.
I am following a tutorial on www.learncpp.com
According to the tutorial, I could define my c++ array such as like this
int main()
{
using namespace std;
enum ArrayElements
{
MAX_ARRAY_SIZE = 5;
};
int anArray[MAX_ARRAY_SIZE];
return 0;
}
But codeblock keep on issuing error
||=== Build: Debug in CH6 (compiler: GNU GCC Compiler) ===|
In function 'int main()':|
|6|error: expected primary-expression before 'enum'|
error: expected ';' before 'enum'|
||=== Build failed: 2 error(s), 1 warning(s) (0 minute(s), 0 second(s)) ===|
I just dont know what is causing the error or is there a problem with the tutorial I am following?
Remove the semicolon inside the enum.
MAX_ARRAY_SIZE = 5;
// ^
If you do have more names inside the enum, separate them with a comma ,
enum COLOR
{
RED,
BLUE,
GREEN
};
replace enum ArrayElements block with following code
int MAX_ARRAY_SIZE = 5;

Array of Pointers assigning value

Works:
int GlobalVar = 5;
int * LPVar[] = {&GlobalVar};
Doesn't work:
int GlobalVar = 5;
int * LPVar[]; // int * LPVar[1] doesn't work too
LPVar[0] = &GlobalVar; // errors here
------ Build started: Project: pointers, Configuration: Release Win32 ------ Compiling... ilovpointers.cpp .\ilovpointers.cpp(9) : error C2466: cannot allocate an array of constant size 0
.\ilovpointers.cpp(9) : error C4430: missing type specifier - int
assumed. Note: C++ does not support default-int .\ilovpointers.cpp(9)
: error C2040: 'LPVar' : 'int []' differs in levels of indirection
from 'int *[1]' .\ilovpointers.cpp(9) : error C2440: 'initializing' :
cannot convert from 'int *' to 'int []'
There are no conversions to array types, although there are conversions to references or pointers to arrays Build log was saved at
"file://f:\Visual Studio
C++\Project1\pointers\pointers\Release\BuildLog.htm" pointers - 4
error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
EDIT:
I solved but got question.
#include <iostream>
#include <stdio.h>
using namespace std;
int GlobalVar = 5;
int * LPVar[1];
void main()
{
LPVar[0] = &GlobalVar;
printf("%i", *LPVar[0]);
cin.get();
}
LPVar is a global array so why it didn't work when I have put it just after definition?
Is the code at file scope?
The answer appears to be yes given the updated code fragment.
If so, you can't have random assignments like LPVar[0] = &GlobalVar; written at file scope. You can only have declarations (without initializers) or definitions (optionally with initializers) at file scope.
In your question, this works (as indeed it should), because there are two variable definitions with initializers.
int GlobalVar = 5;
int *LPVar[] = {&GlobalVar};
This code does not work (as indeed it shouldn't), because the third line is an assignment statement and not a declaration or definition:
int GlobalVar = 5;
int *LPVar[]; // Declaration, not definition
LPVar[0] = &GlobalVar; // Assignment is not allowed outside a function body
Variant:
int GlobalVar = 5;
int *LPVar[1]; // Definition without initializer
LPVar[0] = &GlobalVar; // Assignment is not allowed outside a function body

static int array in a class problem

The following 3 code blocks are the main.cpp, static_class_array.cpp, and static_class_array.h respectively. I'm getting the following error:
static_class_array.cpp||In constructor 'static_array_class::static_array_class()':|
static_class_array.cpp|5|error: cannot convert '<brace-enclosed initializer list>' to 'int' in assignment|
||=== Build finished: 1 errors, 0 warnings ===|
#include "static_class_array.h"
int main()
{
static_array_class* array_class;
array_class = new static_array_class();
delete array_class;
return 0;
}
#include "static_class_array.h"
static_array_class::static_array_class()
{
static_array_class::array[3] = {0,1,2};
}
static_array_class::~static_array_class(){}
#ifndef STATIC_CLASS_ARRAY_H
#define STATIC_CLASS_ARRAY_H
class static_array_class
{
private:
static int array[3];
public:
static_array_class();
~static_array_class();
};
#endif
I think that what you want in the implementation file is:
static_array_class::static_array_class()
{
}
static_array_class::~static_array_class(){}
int static_array_class::array[3] = {0,1,2};
Explanation of error message
"cannot convert 'brace-enclosed initializer list' to 'int' in
assignment"
in submitted code.
This is because the code:
static_array_class::array[3] = {0,1,2};
is interpreted as meaning that {0,1,2} should be assigned to element 3 in the array. Element 3 is of type int, (and incidentally not allocated being the fourth element), so this is like:
int i = 0;
i = {0,1,2};
Hence the error message.
They are not the same type;
Your class is a class which includes a an array -- they other is just an array.
With a static definition of a class member you need to declare the actual instance outside the class, just like with any other static,
int static_array_class::array[3] = {0,1,2}; // note this line is outside the constructor
static_array_class::static_array_class()
{
}
static_array_class::~static_array_class(){}