Say that you have a class that has an array member:
class A
{
private:
uint8_t length;
uint8_t arr[10];
public:
A(uint8_t length, const uint8_t array[]): length(length)
{
memcpy(arr, array, length);
}
};
Then you have a global constant object and you want to use uniform initialization like this:
const A A_CONST{1,{23}};
In this case the compiler gives an error: "invalid conversion from 'int' to 'const uint8_t*"
But this works:
const uint8_t arr[]={23};
const A A_CONST{1,arr};
But then you have an unnecessary global constant "arr" also. I don't understand why the compiler can't cast {23} to const uint8_t* by looking at the constructor. Why is this so and is there a workaround?
The constructor you defined, is equivalent to
A(uint8_t length, const uint8_t *array)
This is, what the compiler is trying to tell.
To have an initialization as in your example, you must use either another type, or a std::initializer_list, e.g.
#include <algorithm>
#include <initializer_list>
A(const std::initializer_list<uint8_t> array)
: length(array.size())
{
std::copy(array.begin(), array.end(), arr);
}
Apart from that, don't use plain arrays or (length, pointer) arguments. Better use modern types like std::array or std::vector, this is less error prone and you get this kind of initialization for free.
If you really need to use an array (instead of std::vector) you can use this example:
#include <cstring>
#include <cstdint>
#include <iostream>
#include <initializer_list>
class A
{
private:
static const uint8_t MAX_LENGTH = 10;
uint8_t length;
uint8_t arr[MAX_LENGTH];
public:
A(uint8_t _length, const uint8_t array[]): length(_length)
{
if (length > MAX_LENGTH) { // to prevent copying out of memory
length = MAX_LENGTH;
}
std::memcpy(arr, array, length);
}
A(std::initializer_list<uint8_t> l): length(l.size())
{
if (length > MAX_LENGTH) { // to prevent copying out of memory
length = MAX_LENGTH;
}
std::initializer_list<uint8_t>::iterator it = l.begin();
for (uint32_t i = 0; (i < length) || (it == l.end()); ++i, ++it) {
arr[i] = *it;
}
}
uint8_t printAllForExample() const {
for (uint32_t i = 0; i < length; ++i) {
std::cout << (int)arr[i] << " ";
}
std::cout << std::endl;
}
uint8_t getLengthForExample() const {
return length;
}
};
int main() {
std::cout << "A_CONST_1:" << std::endl;
const A A_CONST_1{23};
A_CONST_1.printAllForExample();
std::cout << "A_CONST_2:" << std::endl;
const A A_CONST_2{};
std::cout << (int)A_CONST_2.getLengthForExample() << std::endl;
A_CONST_2.printAllForExample();
std::cout << "A_CONST_3:" << std::endl;
const A A_CONST_3{0,1,2,3,4,5,6,7,8,9};
std::cout << (int)A_CONST_3.getLengthForExample() << std::endl;
A_CONST_3.printAllForExample();
std::cout << "A_CONST_4:" << std::endl;
const A A_CONST_4{0,1,2,3,4,5,6,7,8,9,10,11,12};
std::cout << (int)A_CONST_4.getLengthForExample() << std::endl;
A_CONST_4.printAllForExample();
uint8_t data[] = {30,40,50};
std::cout << "A_CONST_5:" << std::endl;
const A A_CONST_5(3, data);
std::cout << (int)A_CONST_5.getLengthForExample() << std::endl;
A_CONST_5.printAllForExample();
return 0;
}
Related
Take a look at this simplified version of what I'm coding and you'll understand the problem...
#include <iostream>
template<typename T, int N = 2>
class Array
{
T m_arr[N]{ 0 };
int m_size = N;
public:
T& operator[](const int& index) { return m_arr[index]; }
};
int main()
{
Array<int, 10>* thing = new Array<int, 10>();
thing[2] = 5;
std::cout << thing[2] << std::endl;
}
Now, obviously the first thing that comes to mind is, hey, just like I overloaded the [] operator, lets overload the = and the << operators, but that wouldn't work, since that is only valid for doing something like this...
thing = whatever;
std::cout << thing << std::endl;
But how could I do it for...
thing[num] = whatever;
std::cout << thing[num] << std::endl;
#include <iostream>
#include <vector>
#include <chrono>
#include <string.h>
std::vector<int64_t> vec;
static const int64_t N = 100000000;
static const int64_t M = N - 1;
void func1() {
std::cout << __FUNCTION__ << std::endl;
std::vector<int64_t> dst;
dst.resize(M);
std::copy(vec.begin(), vec.begin() + M, dst.begin());
}
void func2() {
std::cout << __FUNCTION__ << std::endl;
std::vector<int64_t> dst;
dst.resize(M);
memcpy(&dst[0], &vec[0], M * sizeof(int64_t));
}
void func3() {
std::cout << __FUNCTION__ << std::endl;
std::vector<int64_t> dst(vec);
dst.resize(M);
}
int main(int argc, char* argv[]) {
vec.resize(N);
for (int i = 0; i < N; i++) {
vec[i] = i;
}
auto begin = std::chrono::steady_clock::now();
if (argc == 1) {
func1();
} else if (argc == 2) {
func2();
} else {
func3();
}
auto end = std::chrono::steady_clock::now();
std::cout << "Time difference = "
<< std::chrono::duration_cast<std::chrono::microseconds> \
(end - begin).count()
<< "[µs]" << std::endl;
return 0;
}
I thought std::copy might be slightly faster than copy constructor, as func1() vs func3().
But it turned out that func3() had best performance. Why?
func3
Time difference = 658007[µs]
func2
Time difference = 823092[µs]
func1
Time difference = 838711[µs]
I've also tested std::vector, func1 faster than func3. SomeStruct includes std::string and
struct A {
A(int64_t a) : A_(a) {}
int64_t a_;
};
compile command: g++ test.cpp -std=c++11
I ran several times and the results seem the same.
Copy constructor can copy content of a source vector directly into newly allocated uninitialized memory, especially if contained type is primitive type or POD. Vector implementations are often optimized for this. And on the other hand, call to resize() has to fill newly allocated space with default value (or value that you have specified to resize()), because vector elements cannot be uninitialized. This obviously takes additional time. That's why func1() and func(2) are slower.
I am doing a c++ program. Here's what I have to do: I create an array of the size I want. The array is auto-filled with 0.
With the operator += i have to insert 1 at the place i chose.
Example :
array += 2;
will insert 1 at the index 2 of my array.
But how can I do it ?
My .h file
#ifndef BITARRAY_H
#define BITARRAY_H
#include <ostream>
class bitArray
{
public:
bitArray(int n);
virtual ~bitArray();
bitArray& operator+=(const bitArray&); //this operator
bitArray& operator-=(const bitArray&);
int& operator[] (int x) {
return sortie[x];
}
protected:
private:
int sortie[];
int n;
};
//ostream& operator<<(ostream&, const bitArray&);
#endif // BITARRAY_H
My method in the cpp file :
bitArray& bitArray::operator+=(const bitArray& i)
{
this ->sortie[i] = 1;
return *this;
}
But it does not work. Am I doing the right way?
My error is :
no match for 'operator[]' (operand types are 'int [0]' and 'const bitArray')|
Thank you in advance !
no match for operator[] (operand types are 'int [0]' and 'const
bitArray')|
The error is crystal clear that the operator[] expecting an interger type and what you passing a bitArray class type. Simple fix is to change it to integer.
However, here:
private:
int sortie[];
int n;
it is highly recommended to use std::vector, which gives a contiguous dynamic array whereas sortie[]is static allocation. Something like this:
See live here
#include <iostream>
#include <vector>
#include <cstddef>
class bitArray
{
private:
std::vector<int> sortie;
public:
explicit bitArray(int size): sortie(size) {}
bitArray& operator+=(const std::size_t i)
{
if (0 <= i && i < sortie.size()) // check for (0 <= index < size) of the array
{
this ->sortie[i] = 1;
return *this;
}
else
{
// do your logic! for instance, I have done something like follows:
std::cout << "out of bound" << std::endl;
if(sortie.size() == 0) sortie.resize(1,0); // if the size of array == 0
}
return *this;
}
int operator[] (const std::size_t index)
{
return (0 <= index && index < sortie.size()) ? sortie[index] : -1;
}
};
int main ()
{
bitArray obj(3);
obj += 0; std::cout << obj[0] << std::endl;
obj += -2; std::cout << obj[-2] << std::endl;
obj += 22; std::cout << obj[22] << std::endl;
return 0;
}
Update: Using C++17 feature std::optional, modified the above solution with the optional return type, which should be more readable.
See output in wandbox
#include <iostream>
#include <vector>
#include <cstddef>
#include <optional>
class bitArray
{
private:
std::vector<int> sortie;
public:
explicit bitArray(int size): sortie(size) {}
// optional is used as the return type
std::optional<bitArray> operator+=(const std::size_t i)
{
if (i < sortie.size()) // check for (0 <= index < size) of the array
{
this -> sortie[i] = 1;
return std::optional<bitArray>{*this};
}
std::cout << "out of bound operation+= \t";
return std::nullopt; // std::nullopt to create any (empty) std::optional
}
std::optional<int> operator[] (const std::size_t index)
{
if(index < sortie.size()) return std::optional<int>{sortie[index]};
else
{
std::cout << "out of bound operator[]: ";
return std::nullopt;
}
}
};
int main ()
{
bitArray obj(3);
obj += 0; std::cout << obj[0].value_or(-1) << std::endl;
obj += -2; std::cout << obj[-2].value_or(-1) << std::endl;
bitArray obj1(0);
obj1 += 22; std::cout << obj1[22].value_or(-1) << std::endl;
return 0;
}
Your operator+= takes a bitArray as parameter, but it should take the index where to set the 1 and thats basically what the error message is trying to tell you: There is no overload for the parameters you are trying to use it.
Note that to get such an operator you dont need to write your own array class, but you can provide an overload for std::vector:
#include <iostream>
#include <vector>
template <typename T>
std::vector<T>& operator+=(std::vector<T>& v,size_t index) {
v[index] = 1;
return v;
}
int main() {
auto vec = std::vector<int>(10,0);
vec += 5;
std::cout << vec[5];
return 0;
}
Note that this is a rather uncommon way to implement += (it does not really add anything). I would consider this as misuse of operator overloading and it will lead to obfuscated code. Consider this:
vec[5] = 1;
vs
vec += 5;
In the first line, everybody who is familiar with std::vector will know what it does, while for the second line 90% of the expectations will be off. I guess you are doing this as part of an assignment or homework, though for anything else I would suggest you to stay away from using operator overloads that do anything more than the obvious thing.
*&x
Using c++11, we can write as
* std::addressof(x)
However, is there more readable version of this expression?
constexpr uint64_t lil_endian = 0x65'6e'64'69'61'6e;
// a.k.a. Clockwise-Rotated Endian which allocates like
// char[8] = { n,a,i,d,n,e,\0,\0 }
constexpr auto& arr =
reinterpret_cast<const std::array<char,8> &>
(*std::addressof(lil_endian) );
int main()
{
const auto str = std::string(arr.crbegin()+2, arr.crend() );
std::cout << str << '\n'
<< str.size() << '\n' << '\n';
for (const auto ch : str) {
std::cout << ch << " : " << std::hex << (unsigned int) ch << '\n';
}
}
endian
6
e : 65
n : 6e
d : 64
i : 69
a : 61
n : 6e
godbolt.org/g/9StHsE
wandbox.org/permlink/ZzQ38IlDficO5UOi
* std::addressof(x)
However, is there more readable version of this expression?
x
Vittorio Romeo give you the answer to the second question.
The first supposition is wrong: "Is addressof the readable version of &". addressof is used to get the address of an object even if its class type has an overloaded operator &.
It's unclear what you're trying to do and why you use constexpr.
But there are a couple of issues with your code:
reinterpret_cast is not allowed in a constant expression.
aliasing uint64_t with a std::array is not allowed.
You can, however, work around both of these by aliasing using a const char* in a non-constexpr context. So the following is legal:
#include <iostream>
constexpr uint64_t lil_endian = 0x65'6e'64'69'61'6e;
int main()
{
auto arr = reinterpret_cast<const char*>(&lil_endian);
for (size_t i = 0; i < sizeof(lil_endian); ++i) {
std::cout << arr[i] << " : " << std::hex << (unsigned int) arr[i] << '\n';
}
}
Incidentally also the need for *& disappears.
DEMO
== EDIT ==
If you just need to get a hold of the size of the variable in a generic way, just use sizeof in a function template. For example:
#include <cstdio>
#include <cstdint>
constexpr uint64_t lil_endian = 0x65'6e'64'69'61'6e;
constexpr uint32_t lil_endian32 = 0x65'6e'64'69;
template<typename T>
void printIt(const T& it)
{
auto arr = reinterpret_cast<const char*>(&it);
for (size_t i = 0; i < sizeof(it); ++i) {
putchar(arr[i]);
}
}
int main()
{
printIt(lil_endian);
printIt(lil_endian32);
}
DEMO
I've a vector of structure and it's components, now I want array of this group, below is my code
struct V1
{
USHORT val;
UINT cnt;
USHORT state;
};
struct V2
{
DWORD room;
vector <V1> vref;
bool update_V1(USHORT S1, USHORT S2);
VOID ClearState(USHORT S1);
};
struct V3
{
USHORT block;
vector <V2> V2ref;
bool Update_V2(DWORD S1,USHORT S2,USHORT S3);
VOID ClearState_V2(USHORT S4);
};
struct V4
{
USHORT space;
vector <V3> V3ref;
bool Update_V3(USHORT S1,DWORD S2,USHORT S3);
VOID ClearState_V2(USHORT S4);
};
struct V5
{
USHORT del_1;
vector <V4> V4ref;
bool Update_V4(USHORT S1,USHORT S2,DWORD S3,USHORT S4);
VOID ClearState_V2(USHORT S4);
};
class C1
{
vector<V5> V5ref[2];
bool UpdateGroup(USHORT S1,USHORT S2,USHORT S3,DWORD S4,USHORT S5);
}
bool C1::UpdateGroup(USHORT S1,USHORT S2,USHORT S3,DWORD S4,USHORT S5)
{
vector<V5>::iterator it;
for ( it=V5ref[S5].begin() ; it< V5ref[S5].end(); it++ )
{
if(it->del_1==S2)
{
return grpItr->Update_V4(S1,S2,S3,s4);
}
}
V5 V5local;
V5local.del_1 = S2;
V5local.Update_V4(S1,S2,S3,S4);
V5ref[S5].push_back(V5local);
return true;
}
I tried using vector V5ref[2];
It works for 1st iteration and throws error "assert" for 2nd iteration, what could be the reason. is there any other option to have copies of vectors.
what exactly I want to do is, with parameter S2 being 1, 2, 3, I want diff arrays of the whole vector for S2 = 1, S2 = 2...V5 and it's components should be seperate elements of the array according to S2
I have researched your problem a bit. Since the code is insufficient, we all can only guess what you are doing or not doing there. The debug assertion usually comes if the vector has not enough space allocated. (correct me if I am wrong). So, in this case, before using your vectors, you should use the resize(); method. Here is an example:
struct structure
{
int value1;
char value2;
bool value3;
};
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<structure> vector1;
vector1.resize(1);
vector1[0].value1 = 12;
vector1[0].value2 = 'h';
vector1[0].value3 = true;
return 0;
}
If you test it yourself, you will know that without the vector.resize(1); this won't work at the run-time.
At any given time, a std::vector<> has a constraint, size which is the maximum element number you can access + 1, and a constraint capacity which is how many elements it can contain before it has to move the data to a larger memory allocation.
size determines what you can access. When the vector is created, you cannot access anything. vec[0] is illegal when the vector is empty.
#include <vector>
#include <iostream>
int main()
{
std::vector<int> vec;
std::cout << "initially, vec.size = " << vec.size() << ", cap = " << vec.capacity() << "\n";
// initially, the vector is empty.
// std::cout << vec[0] << '\n'; // undefined behavior, probably a crash
// you can only ever access vec[n] where v < vec.size(),
// this vector is empty, so size() == 0
// Lets add a number to the vector.
vec.push_back(5);
std::cout << "now, vec.size = " << vec.size() << ", cap = " << vec.capacity()
std::cout << "vec[0] = " << vec[0] << '\n';
// std::cout << vec[1] << '\n'; // undefined behavior because 1 >= size()
vec.resize(5);
std::cout << "resized, vec.size = " << vec.size() << ", cap = " << vec.capacity()
vec[1] = 1; // valid, resize made space for vec[0] .. vec[4]
vec[2] = 2;
for (auto it = vec.begin(), end = vec.end(); it != end; ++it)
std::cout << *it << '\n';
return 0;
}
push_back does "vec.resize(vec.size() + 1)" for you, and then inserts the value being 'push_back'ed into the new slot.
resize attempts to make room for extra elements -- if size is 3 and you say resize(5) it will try to make room for 2 new elements.
If the result causes size to exceed capacity then the vector allocates a new array, copies the old data over into it, and releases the old array. This can become very expensive. If you know roughly how big your vector is going to become, you can avoid this relocation by calling reserve()
#include <iostream>
#include <vector>
using std::cout;
struct Stud // will always tell you when it reproduces
{
int m_i;
Stud() : m_i(-1) {}
Stud(int i) : m_i(i) {}
Stud(const Stud& rhs) : m_i(rhs.m_i) { cout << "Copying(Ctor) " << m_i << '\n'; }
Stud& operator=(const Stud& rhs) { m_i = rhs.m_i; cout << "Copying(=) " << m_i << '\n'; return *this; }
};
int main()
{
std::vector<Stud> studs;
studs.push_back(0);
studs.push_back(1);
studs.reserve(5);
studs.push_back(5); // remember, this adds to the back.
studs.push_back(6);
std::cout << "size of studs " << studs.size();
return 0;
}
Based on this
bool Update_V4(USHORT S1,USHORT S2,DWORD S3,USHORT S4);
I am guessing that you are trying to simulate multi-dimensional arrays of some kind, and you are doing something like
V4Ref[S1]
without checking
if (S1 < V4Ref.size())
C++ has a function 'assert' which will cause a Debug build application to terminate if a condition is not met.
#include <cassert>
#include <vector>
int main()
{
std::vector<int> vec;
assert(vec.size() == 0);
vec.push_back(1);
vec.resize(5);
vec.push_back(5);
assert(vec.size() == 10); // expect to crash here.
return 0;
}
You could use this to help catch bad sizes:
bool V4::Update_V4(USHORT S1,USHORT S2,DWORD S3,USHORT S4)
{
assert(S1 < V4ref.size());
return V4ref[S1].Update_V3(S2, S3, S4);
}