I have this problem of conversion with this code using c++11 standard:
#include<unordered_set>
struct B
{
int x, y;
};
class A
{
struct hash
{
std::size_t operator()( int* const a ) const
{
return std::hash<int>()( *a );
}
};
struct equal_to
{
std::size_t operator()( int* const a, int* const b ) const
{
return std::equal_to<int>()( *a, *b );
}
};
private:
std::unordered_set< int*, hash, equal_to > set;
public:
void push( const B& b )
{
set.insert( &b.x );
}
};
Anyone know why is that? I can I solve the problem removing the "const" modifier in the argument of "push". But I don't want it because argument "b" isn't modified.
Edit.: My simplification of code has produced a unreferenced adress. I've make a struct B remove it.
The key of the set is declared as being a pointer-to-int, an int*. But this:
void push( const B& b )
{
set.insert( &b.x );
}
is passing the address of a constant int, an int const*, hence the compiler error.
Removing the const from the argument would resolve the compiler error, as would making the key type an int const*, but both these solutions would:
permit some other part of the program, with non-const access to a B instance that was passed to push(), to change a value of one of the keys within the set and break the set invariant:
A a;
B b1{17, 22};
B b2{30, 22};
a.push(b1);
a.push(b2);
b1.x = 30; // set no longer contains unique keys.
introduce a dependency of the set on the lifetime of the object referenced by b:
A a;
a.push({14, 23}); // a now contains a dangling pointer.
The safest solution is to store an int as the key, see http://ideone.com/KrykZw for online demo (thanks to bitmask for comment).
Possible solutions:
Dynamically copy b.x. Or,
Use int const* as the key. Or preferably (avoiding explicit dynamic allocation),
Use int as the key, instead of an int* (see http://ideone.com/KrykZw)
Related
Consider the following code.
class SomeClass{};
class AnotherClass
{
public:
SomeClass c1;
SomeClass c2;
SomeClass c3;
const SomeClass* someClassArray[3] = { &c1, &c2, &c3 };
const SomeClass** GetSomeClassArray ()
{
return someClassArray;
}
};
int main ()
{
AnotherClass anotherClass;
const SomeClass** someClassArray = anotherClass.GetSomeClassArray ();
SomeClass* someClass2 = new SomeClass;
someClassArray[0] = someClass2; //This should not be allowed
}
I am declaring the array someClassArray as const. I am specifying the return type of GetSomeClassArray as const SomeClass** and yet, I am still allowed to modify the contents of the array later in the main function.
I also noticed that adding const specifier to the method as such: const SomeClass** GetSomeClassArray () const causes an error.
Why is this the case?
Your interpretation of what is const is wrong.
The term const binds left (unless it is on the very left then in binds right).
// so This
const SomeClass* someClassArray[3] = { &c1, &c2, &c3 };
// Equivelent to this:
SomeClass const * someClassArray[3] = { &c1, &c2, &c3 };
So now we can read the type easier. Types are read right to left.
SomeClass const * [3]
^^^ Array of
^ Pointer To
^^^^^^^^^^^^^^^ const SomeClass
So you have an array of pointer to "const SomeClass". So the "SomeClass" object are const but the pointers are not. If you want the array to be imutable then make the pointers also const.
SomeClass const * const [3]
^^^ Array of
^^^^^^^ const Pointer To
^^^^^^^^^^^^^^^ const SomeClass
That being said. That's probably not the best way of declaring that.
Why not just declare an array of objects?
const SomeClass someClassArray[3];
Also a return type of ** is loosing information on the size of the array, so that is not the greatest.
// Updated to put const in correct place first.
SomeClass const *const * GetSomeClassArray() {return someClassArray;}
// The syntax for return an array by reference is
// super non intuitive. I could spend 30 minutes
// looking up the exact syntax or we can let the
// compiler do it for you.
auto& GetSomeClassArray() {return someClassArray;}
or
auto const& GetSomeClassArray() {return someClassArray;}
You want to keep the type information about the size of the array as this will help in sveral ways.
Since we are using C++ you can consider using std::array rather than a C array (or std::vector potentially).
const std::array<SomeClass, 3> someClassArray;
When you declare const SomeClass* p, it is *p that is const. So when you declare const SomeClass** p, it is **p that is const and not *p. If you want *p to be const, you have to put const SomeClass* const* p.
I want to have class scope alias to the vector from an argument.
For exapmale:
class Solution {
private:
vector<int> b; // I want that &b = a, where a from function solve
int f(int i) {
// here I want to use vector<int> a,
// not passing it as a function argument every time
}
public:
int solve(vector<int>& a) {
// here I want to do smth like b = a; which works for O(1)
}
};
Unfortunatelly, I can't just declare vector<int> &b; , because of the error:
declaration of reference variable 'b' requires an initializer
Could you please, explain how to do it in C++11/14?
Update: I can't change the declaration of int solve(vector<int>& a), the interface provided from outside.
Update: I've changed the code to the more explicit. Looks like I shouldn't do again because in answers and comments people use original variable names. I'm sorry, don't have much experience with StackOverflow.
Maybe this?
class Solution {
public:
vector<int> a;
int maxCoins(const vector<int>& _a) { // const because copying
a.assign( _a.begin(), _a.end() );
}
};
But know that you can also do this if you want a reference to the original vector<int> rather than a copy:
class Solution {
public:
vector<int> & a;
int maxCoins(vector<int>& _a) : a( _a ) {}
};
Update
This is probably closest. You cannot re-initialize a reference, but then this is exactly the use-case for pointers.
class Solution {
public:
vector<int> * a;
int f(int i) {
a->size(); // can access indirectly
(*a)[1]; // element access is slightly trickier
vector<int> & _a = *a; // or can create a direct ref
_a.size();
}
int solve(vector<int>& _a) {
a = &_a; // store address to _a. a reference is like any local variable unless doing something funny
}
};
Update 2 - using no pointers
#include <functional>
class Solution {
public:
// vector<int> a;
typedef vector<int> datatype;
datatype blankref;
std::reference_wrapper<datatype> a = blankref;
int f(int i) {
vector<int> & _a = a;
}
int solve(vector<int>& _a) {
a = std::ref(_a);
}
};
You can't avoid the fact that references are assign-once. References in a class instance have to be assigned using initializer syntax. To have a re-usable reference, you need to have a newly initialized object each time.
To help us here, thanks to advice in comments, there is std::reference_wrapper<T> type that can hold instances of references. It can be assigned to using std::ref( _a ) repeatedly.
Honestly pointers are not inelegant when used right, imo. It comes down to use case and what you believe you would need. Performance wise this probably won't be as good as with pointers (because of temporary objects being constructed), though no guarantees... it should perform similarly in any case.
I have the following code:
#include <map>
using namespace std;
struct A {};
map</*const*/ A *, int> data;
int get_attached_value(const A *p) {
return data.at(p);
}
void reset_all() {
for (const auto &p : data) *p.first = A();
}
My problem is that this code fails on a type error both when I comment and uncomment the const in the type of data. Is there any way I can solve this without using const_cast and without losing the const in get_attached_value?
The problem seems to be in the pointee type, which has to be the same in both pointer declarations (map key type and the get_attached_value's argument).
OP's code uses const A*, which is a pointer to a const instance of class A (an alternative spelling is A const *). Leaving this const in both map declaration and in get_attached_value' argument almost works, but reset_all does not allow you to assign a new value to *p.first, because the resulting type is A const& (which cannot be assigned into).
Removing both consts works as well, but OP wants to keep a const in get_attached_value.
One solution for OP's requirements, keeping as many consts as possible, seems to be to change the pointer type to a const pointer to a non-const instance of A. This will keep reset_all working, while allowing to use a const pointer in both map declaration and get_attached_value's argument:
#include <map>
using namespace std;
struct A {};
map<A * const, int> data;
int get_attached_value(A * const p) {
return data.at(p);
}
void reset_all() {
for (const auto &p : data)
*p.first = A();
}
Another possible solution, with map's key as non-const but the get_attached_value's parameter const, could use std::lower_bound with a custom comparator to replace the data.at() call:
#include <map>
#include <algorithm>
using namespace std;
struct A {};
map<A*, int> data;
int get_attached_value(A const * const p) {
auto it = std::lower_bound(data.begin(), data.end(), p,
[] (const std::pair<A* const, int>& a, A const* const b) {
return a.first < b;
}
);
return it->second;
}
void reset_all() {
for (const auto &p : data)
*p.first = A();
}
However, this solution will be significantly less efficient than one that would use map's native search functions - std::lower_bound uses linear search when input iterators are not random access.
To conclude, the most efficient solution in C++11 or lower would probably use a const pointer as the map's key, and a const_cast in the reset_all function.
A bit more reading about const notation and pointers can be found here.
i am searching for a way to store different type of pointers in a map without using void* for obvious reasons. I actually know the types of the pointers at compile-time and these pointers as well as their types need to be const while their values need to be changed from times to times. The types are always some kind of numerical types.
Background:
The variables behind these pointer are actually always global variables which need to changed if an specific event happens. Eachs event has an Id, the first member of that map, which changes the variable to a value transported by that event as a string.
So far i think boost::variant would do the trick. I am new to variant and i dont know whether the following would work as expected regarding the constness, but i assume after reading the f*cking manual that it should be ok. The main issue still is how to change that value behind that pointer utilising the standard conversions:
class Data{
public:
typedef boost::shared_ptr<Data> Ptr;
typedef boost::variant<double*, float*, unsigned int*, int*, unsigned short*, short*, unsigned char*, char*> PodPointerVariant;
double factor;
const PodPointerVariant varPointer;
Data(PodPointerVariant variable) :
factor(0.0),
varPointer(variable) {}
}
std::map<unsigned int, Data::Ptr> dataMap;
unsigned int intValue;
float floatValue;
void main()
{
intValue = 1;
Data::Ptr newEntry(new Data(&intValue));
newEntry->factor = 1.1;
dataMap->insert(std::make_pair(1,newEntry));
// Omitted find key and safety if not found...
unsigned int eventId = 1;
*(dataMap[eventId]->varPointer) = 2.1 * dataMap[1]->factor; // Should be automagically converted to 2 because the pointer is of type unsigned int, but gives a compiler error? I cant dereference that normally.
}
Is there an easy way to dereference like this? Maybe using a visitor class? Or anything else? Ideally Data->varPointer shall only be initialised once and only the value may be changed, like a "double * const", so i gets checked at compiled-time if somebody messes around with that pointer.
Thank you!
UPDATE
After some trial and error i found out that it indeed works as expected. This is what i've done this far:
template<typename U>
struct DeRefAssignVisitor : public boost::static_visitor<>
{
U x;
double factor;
DeRefAssignVisitor(U x, double factor) : x(x), factor(factor) { }
template <typename T>
void operator()(T* const p) const
{
*p = (T)(x * factor);
}
};
class Data{
public:
typedef boost::shared_ptr<Data> Ptr;
typedef boost::variant<double * const, float* const, unsigned long* const, long* const, unsigned short* const, short* const, unsigned char* const, char* const, plcbit* const> PodReferenceVariant;
double factor;
const PodPointerVariant varPointer;
Data(PodPointerVariant variable) :
factor(0.0),
varPointer(variable) {}
template <typename T>
void setPointerValue(T value) { boost::apply_visitor(DeRefAssignVisitor<T>(value, this->factor), this->varPointer); }
}
std::map<unsigned int, Data::Ptr> dataMap;
unsigned int intValue;
float floatValue;
void main()
{
intValue = 1;
floatValue = 2.111;
Data::Ptr newEntry(new Data(&intValue));
newEntry->factor = 1.1;
dataMap->insert(std::make_pair(1,newEntry));
// Omitted find key and safety if not found...
unsigned int eventId = 1;
dataMap[eventId]->setPointerValue(floatValue); // Works like a charme: converting compatible types automagically :-)
}
Templates 4TW :-D Thanks everybody!
Actually you can use visitors from boost.
class AssignVisitor : public boost::static_visitor<>
{
public:
double x;
AssignVisitor(double x) : x(x) { }
void operator()(int* p)
{
*p = (int)x;
}
void operator()(double* p)
{
*p = (double)x;
}
//and so on
};
And then
boost::apply_visitor(AssignVisitor(2.1 * dataMap[1]->factor), dataMap[eventId]->varPointer);
I have a class which hold an array "float ** table". Now I want to have member function to return it, but don't want it to be modified outside of the class. So I did this:
class sometable
{
public:
...
void updateTable(......);
float **getTable() const {return table;}
private:
...
float **table;
}
This compiles OK when I call getTable with a constant object. Now I tried to
make it safer by declaring getTable as "const float **getTable()". I got
the following compilation error:
Error:
Cannot return float**const from a function that should return const float**.
Why? How can I avoid table to be modified out side of the class?
Declare your method like this:
float const* const* getTable() const {return table;}
or
const float* const* getTable() const {return table;}
if you prefer.
You can't assign a float** to a float const** because it would allows to modify a const object:
float const pi = 3.141592693;
float* ptr;
float const** p = &ptr; // example of assigning a float** to a float const**, you can't do that
*p = π // in fact assigning &pi to ptr
*ptr = 3; // PI Indiana Bill?
C and C++ rules differ about what is allowed.
C++ rule is that when you add a const before a star, you have to add a const before each following one.
C rule is that you can only add a const before the last star.
In both languages, you can remove a const only before the last star.
You could declare your method as
const float * const * const getTable() const {return table;}
but even this (the outermost const - next to the function name) would not prevent the client to try to delete it.
You could return reference instead, but the best would be to use an std::vector for table and return const ref to it - unless using a C style array is a must
Though you can clearly type the syntax just like that, I find it much more readable to define some typedefs for multiple-dimension arrays.
struct M {
typedef double* t_array;
typedef const double t_carray;
typedef t_array* t_matrix;
typedef const t_carray* t_cmatrix;
t_matrix values_;
t_cmatrix values() const { return values_; }
t_matrix values() { return values_; }
};