how to assign array of struct to class variable without memcpy - c++

I'm creating a class were doing something with an array of struct, but the problem is I cannot assign array reference to the object.
already trying to find the solution, but only works with copying the entire array to the object variable with memcpy, how to do this differently without copying the array?
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define arrayLength(array) (size_t)((sizeof array) / (sizeof array[0]))
typedef struct someStruct {
int id;
char *name;
} someStruct;
class someClass {
private:
someStruct *list;
public:
someClass(someStruct const *const listData) { list = listData; }
};
int main() {
someStruct list[255] = {
{1, "one"},
};
someClass object(list);
return 0;
}
error: invalid conversion from 'const someStruct*' to 'someStruct*' [-fpermissive]
someClass(someStruct const *const listData) { list = listData; }

You are supplying a const pointer, then assigning a non-const pointer to that const pointer. The compiler is not letting you downgrade const to non-const.
Make someClass's list a const pointer, or remove the const qualifiers from the initializer parameters.

if you are not sure about compiler error message,
here it is in short:
in constructor body you have tried to assign pointer to const value to pointer to value, implicates that if compiler let you, you will try to change const value using pointer and for that you certainly can't use pointer to const. At least not without any special purpose casting.
This is not the only thing in your code sample that should be changed, but you can start from there.

Related

initialize const char[] as non-static class member

class foo {
public:
const char name[100];
foo(const char name[]) : name(name) {};
};
int main(){
foo("test");
return 0;
}
Does not compile. How do I initialize const char[] non-static class member?
You have different option, depending on what you want to achieve.
arrays in C++ are strange beasts, they do not behave like most other types, in particular they decay to pointers and do not have copy-constructors (unless wrapped in a structure/class).
foo(const char name[]) does not take an array by value/by copy, it takes a pointer (yes, the syntax is confusing).
Thus name(name) is trying to initialize an array with a pointer.
If this would compile, it would make it super-easy to overflow the stack by accident, as there is no guarantee that the pointer name points to an array that is long at most 100 elements.
Solution 1
Use a more suitable construct - use a string.
From your snippet, it seems you want to store a piece of text (variable named name, initialisation with a string-literal...), so a std::string or other string-like class (even const char*) is a better construct.
class foo {
public:
std::string name;
explicit foo(std::string name_) : name(name_) {};
};
int main(){
foo("test");
}
Solution 2
Use a better array
If you really need to store/copy an array, consider using std::array (since c++11)
#include <array>
class foo {
public:
std::array<char, 100> name;
explicit foo(std::array<char, 100> name_) : name(name_) {};
};
int main(){
foo(std::array<char, 100>{"test"});
}
Solution 3
Pass the array by const-ref.
There are use--cases where you really want to use an array.
In this case you need to pass the value by reference, and copy the content with std::initializer_list (since c++14, but it's possible to emulate in c++11)
#include <utility>
class foo {
template <std::size_t... PACK1>
explicit foo(const char (&name_)[100], std::index_sequence<PACK1...>)
: name{ name_[PACK1]... }
{}
const char name[100];
public:
explicit foo(const char (&name_)[100])
: foo(name_, std::make_index_sequence<100>{})
{}
};
int main(){
const char hello[100] = "hello!";
foo f = foo(hello);
}
const char (&arr)[100] is an array of length 100 passed by const-reference.
As arrays do not have copy-constructors, we need to use index_sequence to initilize all members.
Solution 4
Use pointers and initialize the array in 2 phases.
Passing the array by const-reference means you need to create such a big array beforehand, and that you cannot pass a string literal which length is not exactly 101 (because of terminatig \0).
#include <cstring>
class foo {
const char name[100];
public:
// constructor requires copy... unsure if needs to be so
explicit foo(const char* name_)
{
std::copy(name_, name_ + std::strlen(name_), name);
}
};
int main(){
const char test[100] = "test!";
foo f = foo(test);
}
i would sugest to use a std::string if you are using c++, but if the const char [] is a must, here is the solution, basically you just copy some portion of the shortest string to the array of size 100, leaving unfilled the extra space(ie: name will result in name = ['t','e','s','t','\0',...]
https://www.cplusplus.com/reference/cstring/memcpy/
https://ideone.com/91nC60
#include <iostream>
class foo{
const char *name;
public:
void showme(){
std::cout<<name<<std::endl;
};
foo(const char *_name) : name(_name) {
};
};
int main(){
foo a("test");
a.showme();
return 0;
}
or
#include <iostream>
struct foo{
const char *name;
void showme(){
std::cout<<name<<std::endl;
};
};
int main(){
foo a={
.name="test"
};
a.showme();
return 0;
}

Why did I have to change the type of a the value of a map from & to (int*)&

I have the function getElement that returns a pointer to a value of a map.
int * getElement(const int &key) const {
return (int*)&m.find(key)->second;
}
If I use for instance return &m.find(key)->second it creates a compilation error:
In member function 'int* A::getElement(const int&) const': 12:30:
error: invalid conversion from 'const int*' to 'int*' [-fpermissive]
Why do I have to change &m.find(key)->second to (int*)&m.find(key)->second in order for the code to compile correctly?
#include <iostream>
#include <string>
#include <map>
class A {
public:
void addElement(const int &key, const int &value) {
m.emplace(key,value);
}
int * getElement(const int &key) const {
return (int*)&m.find(key)->second;
}
private:
std::map<int,int> m;
};
int main()
{
A a;
int value = 1;
int key = 1;
a.addElement(key,value);
int * x = a.getElement(1);
std::cout << *x << std::endl;
return 0;
}
Why do I have to change &m.find(key)->second to (int*)&m.find(key)->second
You don’t. In fact, doing so potentially creates an error. Instead, remove the const qualifier on your member function if you really want to modify the map values. Or return a const int* instead of an int* from the function.
To clarify, when you specify a member function as being const, then the this pointer inside that function becomes a pointer to a const instance of your class. This, in turn, makes its data members const, transitively.
As a consequence, your std::map<int, int> becomes a std::map<int, int> const inside your getElement function. Furthermore, std::map::find has an overload for const maps that returns a const_iterator — hence the const int*.
In fact, be careful: std::map::iterator isn’t necessarily T*. So you shouldn’t return int* or const int* — you should return std::map<int, int>::iterator (or …::const_iterator).
this membre fonction
int * getElement(const int &key) const
is constant so you can access all data membre as constant
and int* is different from const int*

Why can I modify the class with a const function in C++11?

I'm a bit newbie to CPP and I don't know why the setValue() const works meanwhile it's a const.
Why the class allows modification from a const public
It seems really odd, there is no error on g++ -Wall or with MS Visual C++
Here is my code:
main.cpp
#include <iostream>
#include <cassert>
#include "DArray.h"
int main(void)
{
DArray darray(1);
darray.setValue(0, 42);
assert(darray.getValue(0) == 42);
darray.~DArray();
system("pause");
return 0;
}
DArray.h
class DArray
{
private:
int* tab;
public:
DArray();
DArray(unsigned int n);
~DArray();
int& getValue(unsigned int n) const;
void setValue(unsigned int n, int value) const;
};
DArray.cpp
#include "DArray.h"
DArray::DArray()
{
}
DArray::DArray(unsigned int n)
{
tab = new int[n];
}
DArray::~DArray()
{
delete[] tab;
tab = nullptr;
}
int& DArray::getValue(unsigned n) const
{
return tab[n];
}
void DArray::setValue(unsigned n, int value) const // HERE
{
tab[n] = value;
}
It is because you do not modify it. When you do:
int* tab
tab contains only an address. Then in
void DArray::setValue(unsigned n, int value) const // HERE
{
tab[n] = value;
}
You do not modify this address, you modify some memory after it. Thus you do not modify your class.
If instead, you used
std::vector<int> tab
You would have an error in setValue because you would modify an element of your class.
First of all, don't call explicitely the destructor of your class, this will be called when the variable goes out of scope automatically.
darray.~DArray();
What you are promising with const in the method is that the member variables will not be modified. The variable int* tab is a pointer to an int. With your setValue function you are not changing the address of the pointer (which is promised not to be changed by the final const in the signature of your method) but the int value pointed by it. This is fine.
However, if you change the pointer address, for example with tab = nullptr, you will see a compiler error like:
error: assignment of member 'DArray::tab' in read-only object
Why can I modify the class with a const function in C++11?
It is possible to modify mutable state of the object. It is technically also possible to modify the non-mutable state using const_cast, but it would be a bad idea to do so because if the object itself is const, then behaviour would be undefined.
That's however not what you do in this code.
why the setValue() const works meanwhile it's a const.
Because it doesn't modify any member of this. It modifies an array that is pointed by a pointer to non-const. Constness of a member function, or constness of the object is not transfer to an indirectly pointed object.

C++. Why I can't compile this code? What is wrong with removing constness using const_cast?

I have some problem removing constness using const_cast. Error msg says "Conversion is a valid standard conversion....."
What is the nature of this problem? Why should I use C-style cast instead?
"error C2440: 'const_cast' : cannot convert from 'const size_t' to 'size_t'"
"Conversion is a valid standard conversion, which can be performed implicitly or by use of static_cast, C-style cast or function-style cast"
template<typename T>
const IFixedMemory* FixedMemoryPkt<T>::operator=(const IFixedMemory* srcObj)
{
// doesn't remove constness this way. why?
const_cast<char*> (this->m_Address) = (char*)srcObj->GetAddress();
// compile this way, but maybe(?) undefined behaviour
// const_cast<char*&> (this->m_Address) = (char*)srcObj->GetAddress();
// doesn't doesn't work too
const_cast<size_t> (this->m_Size) = (size_t)(srcObj->GetSize());
// const_cast<size_t> (this->m_Size) = 0;
return this;
}
template<typename T>
class FixedMemoryPkt : public IFixedMemory
{
private:
const size_t m_Size;
const char* m_Address;
}
class IFixedMemory
{
public:
virtual const char* GetAddress() const = 0;
virtual size_t GetSize() const = 0;
}
const_cast is used to convert from pointers or references to const objects, to their non-const equivalents. However, you can't use them to modify the object they refer to if the object itself is const. There is no valid way to modify m_Size; if you want to modify it, then don't declare it const.
You do not need a cast to assign to the pointer, since the pointer itself is not const:
this->m_Memory = srcObj->GetAddress();
If you did want the pointer itself to be const, then the const would come after the *:
char * const m_Address;
and, as with the const size_t, you wouldn't be able to reassign it.
As the error says, you can convert a const value into a non-const temporary copy of that value without a cast; but you couldn't assign to that temporary.
You're attempting to cast the size_t thing to an r-value, and you can't assign to an r-value.
I have to say that casting away the constness of your size_t member is pretty evil. That's what mutable is for. And AFAICS your 1st const cast does nothing useful.
Works this way now...
template<typename T>
const IFixedMemory* FixedMemoryPkt<T>::operator=(const IFixedMemory* srcObj)
{
this->m_Address = srcObj->GetAddress();
this->m_Size = srcObj->GetSize();
return this;
}
template<typename T>
class FixedMemoryPkt : public IFixedMemory
{
private:
const char* m_Address;
size_t m_Size;
};

Casting from string to void* and back

is possible to re-map STL class object from void* ?
#include <string>
void func(void *d)
{
std::string &s = reinterpret_cast<std::string&>(d);
}
int main()
{
std::string s = "Hi";
func(reinterpret_cast<void*>(&s));
}
Use static_cast to convert void pointers back to other pointers, just be sure to convert back to the exact same type used originally. No cast is necessary to convert to a void pointer.
This works for any pointer type, including pointers to types from the stdlib. (Technically any pointer to object type, but this is what is meant by "pointers"; other types of pointers, such as pointers to data members, require qualification.)
void func(void *d) {
std::string &s = *static_cast<std::string*>(d);
// It is more common to make s a pointer too, but I kept the reference
// that you have.
}
int main() {
std::string s = "Hi";
func(&s);
return 0;
}
I re-wrote as following,
#include<string>
void func(void *d)
{
std::string *x = static_cast<std::string*>(d);
/* since, d is pointer to address, it should be casted back to pointer
Note: no reinterpretation is required when casting from void* */
}
int main()
{
std::string s = "Hi";
func(&s); //implicit converssion, no cast required
}
You code shouldn't compile.
Change
std::string &s = reinterpret_cast<std::string&>(d);
to
std::string *s = static_cast<std::string*>(d);
EDIT:
Updated code. Use static_cast instead of reinterpret_cast
Yes, it is possible, but you are trying to cast from a pointer to void *, then to a reference. The reinterpret_cast operator only allows casting back to exactly the same type that you started with. Try this instead:
void func(void *d)
{
std::string &s = *reinterpret_cast<std::string*>(d);
}