std::vector with const pointer to const object does not compile - c++

I get a whole lot of errors from gcc when trying to complie this method. zones_ is a
std::map<int,std::vector<Zone const * const>>
That is a private member of MyClass.
//get unique zones
std::vector<Zone const* const> MyClass::getZones() const {
std::vector<Zone const * const> zones; //why can I not do this???
std::map<Zone const * const,int> zone_set;
for(auto & pair : zones_) {
for(Zone const * const z : pair.second) {
if(zone_set.count(z) == 0) {
zone_set[z] = 1;
zones.push_back(z); //cannot do this
}
}
}
return zones;
}
Can I have a vector of const pointers to const objects?

no, the element type cannot be const (can be pointer to const type though)
also there is no need for this, since when you return a const reference to your vector, the access to the elements will be const_reference: http://www.cplusplus.com/reference/vector/vector/operator[]

No. In general, elements of vectors can't be const since they have to be moved when the vector's array needs reallocating. You'll have to store Zone const *; or perhaps use a different container type (list, deque or possibly set), if you really need constant elements.

Related

Pointer to const object with emplace_back

I don't understand when we can use const variables/objects in collections (particularly with emplace). The below code works with const objects directly but not when using pointers to const objects.
#include <list>
class MyData { };
int main() {
std::list<std::pair<int, MyData>> collection1{};
std::list<std::pair<int, MyData*>> collection2{};
const MyData someData{};
const MyData* someDataPtr = &someData;
collection1.emplace_back(1, someData);
//collection2.emplace_back(1, someDataPtr); //Messy template error!
}
I assume there's not much advantage to using emplace_back over push_back for pointers, but I'm using std::pair to illustrate that the other part of the pair could be something big/costly.
Specifically, my question is why does emplace_back work with a const object but not a pointer to a const object? Is there a reasonable way to achieve the latter?
For anyone wondering about the use-case, I have a member function which is passed the constituents of the pair, does some processing (but should not change any data) and then emplaces the pair to the collection. Something like:
void add_to_schedule(const int id, const MyData* myData) {
//some processing
this->collection.emplace_back(id, myData);
}
const MyData* can't be converted to MyData* implicitly. That means std::pair<int, MyData*> can't be constructed from {1, someDataPtr} while someDataPtr is a const MyData*.
Under the same logic,
MyData* p = someDataPtr; // fails
MyData m = someData; // fine
As the workaround, you can change someDataPtr to MyData*, or change the std::list to std::list<std::pair<int, const MyData*>>.

construct a vector in range without copying

I have a class that wraps a big array of bytes that are network packets. The class implements a queue and provides (among others) front() function that returns a const vector of bytes that constitute the oldest packet in the queue.
class Buffer{
unsigned char data[65536];
unsigned int offset;
unsigned int length;
[...]//other fields for maintaining write ptr etc.
public:
const std::vector<unsigned char> front(){
return std::vector<unsigned char>(data + offset, data + offset + length);
}
//other methods for accessing the queue like
//pop(), push(), clean() and so forth...
[...]
}
The performance of above implementation of front() function suffers from unnecessary copying bytes from the range occupied by the current packet. Since the vector is const, there is no need of making a copy of the data. What I want is to create a vector on the data that are already stored in the buffer. Of course destructor of the vector should not deallocate the memory.
You have some options available to you:
Rather than returning a vector, just return a const char*:
const char* front() {
return data;
}
Consider using a standard container, such as a string data as your Buffer member. This will allow you to do:
const string& front() {
return data;
}
The best option though is if you have C++17 or access to experimental::string_view you could just do:
const string_view front() {
return string_view(data);
}
Just a convention comment, there is going to be an expectation of front that it will behave like other standard containers, which:
Returns a reference to the first element in the container.
Calling front on an empty container is undefined.
[source]
Bringing front to apply to bare on fixed size arrays was also discussed by the C++ standards committee: front and back Proposal for iterators Library
As it is this method more closely resembles data, which:
Returns a pointer to the block of memory containing the elements of the container.
[source]
If you're looking to avoid unnecessary copying then you'll need to return a view into the data. You can either provide a front_begin() and front_end() set of functions:
const char *front_begin() const
{
return data + offset;
}
const char *front_end() const
{
return data + offset + length;
}
Or write a wrapper class:
class Data
{
private:
const char *m_Begin;
const char *m_End;
public:
Data(const char *begin, const char *end) : m_Begin(begin), m_End(end)
{
}
const char *begin() const
{
return m_Begin;
}
const char *end() const
{
return m_End;
}
}
And have your front() method return one of these:
Data front()
{
return Data(data + offset, data + offset + length)
}
If you're using C++11 then you can use a Data instance in a ranged based for loop:
Data data = buffer.front();
for(char c : data)
{
// Do something with the data
}

Std::vector<struct> to const std::vector<const struct>*

I have private variable std::vector<some struct> Can i somehow pass the vector to function return value, but with no "write" access, so you will not be able to add new elements into it, and you won't be able to modify the elements(e.g. const std::vector<some const struct>*. How can i do that? The only idea i have is to create a new vector with constant pointers to existing elements. Is there a better solution?
You can't modify the elements of a vector via a pointer or reference to const vector. So the following would be safe:
const std::vector<some_type>* get_pstuff() const { return &the_vector; }
const std::vector<some_type>& get_rstuff() const { return the_vector; }
On the other hand, it might be more idiomatic to return const_iterators to the begin and end of the vector:
std::vector<some_type>::const_iterator cbegin() const { return the_vector.cbegin(); }
std::vector<some_type>::const_iterator cend() const { return the_vector.cend(); }

Is std::string an object?

just looking in optimizing some std::map code. The map contains objects, accessed via the string-identifier.
Example:
std::map<std::string, CVeryImportantObject> theMap;
...
theMap["second"] = new CVeryImportantObject();
Now, when using the find-function as theMap->find("second"), the String is converted into std::string("second"), which causes new string allocations (over all when using IDL=2 with Visual Studio).
1. Is there a possibility to use a string-only class to avoid such allocations?
Intentionally I've tried to use another String-Class as well:
std::map<CString, CVeryImportantObject> theMap;
This code works also. But CString indeed is an object.
And: If you remove an object from the map, I'll need to release both the related object and the key, do I?
Any suggestions?
Now, when using the find-function as theMap->find("second"), the
String is converted into std::string("second"), which causes new
string allocations (over all when using IDL=2 with Visual Studio).
This is a Standard issue, which is fixed in C++14 for ordered containers. The newest version of VS, VS 14 CTP (which is a pre-release) contains a fix for this issue, as will new versions of other implementations.
If you need to avoid allocations, you can try a class like llvm::StringRef which can refer to std::string or string literals interchangably, but then you will be left trying to handle the ownership externally.
You can try something like unique_ptr<char[], maybe_delete> that sometimes deletes the contents. This is a bit of a mess to interface with though.
And: If you remove an object from the map, I'll need to release both
the related object and the key, do I?
The map will automatically destruct the key and value for you. For a class which frees it's own resources like std::string, which is the only sane way to write C++, then you can erase without worrying about resource cleanup.
If you always use string constants as keys, you can use const char * as key type in map when you use proper comparator:
struct PCharCompare {
bool operator()( const char *s1, const char *s2 ) const { return strcmp( s1, s2 ) < 0; }
};
std::map< const char *, CVeryImportantObject, PCharCompare> theMap;
Note: you have to be careful and need to understand how it works, as it can easily lead to UB:
void foo() {
char buffer[256];
snprintf( buffer, sizeof( buffer ), "blah" );
theMap.insert( std::make_pair( buffer, Object ) );
} // ups dangled pointer in the map
As for optimization, it is very unlikely that std::string creation is a culprit. you may try to use std::unordered_map or something similar for optimization
Now, when using the find-function as theMap->find("second"), the
String is converted into std::string("second"), which causes new
string allocations
Not necessarily. VC uses Small-String Optimisation (SSO). This means that for a string as short as "second", no allocation on the heap should take place at all; the characters will instead be stored directly in the temporarily created std::string object.
This is still not free (because the std::string has to be created, albeit without any dynamic allocation happening inside), but should be good enough. Is it really a concern for you? Chances are very high that it does not cause any measurable performance decrease.
Is there a possibility to use a string-only class to avoid such allocations?
Not really, except of the C++14 fix mentioned in other answers. Using char const * as the key type is very dangerous, because std::map will only store the actual addresses, not copies of the keys.
If I were you and if I really experienced performance problems, I'd just not use std::map directly but create my own container class to wrap a std::map<char const *, T, CustomComparison> and do the hard pointer work inside.
template <class ValueType>
class FastStringMap
{
private:
struct Comparison
{
bool operator()(char const *lhs, char const *rhs) const
{
return strcmp(lhs, rhs) > 0;
}
};
typedef std::map<char const *, ValueType, Comparison> WrappedMap;
WrappedMap m_map;
public:
typedef typename WrappedMap::iterator iterator;
typedef typename WrappedMap::const_iterator const_iterator;
bool insert(char const *key, ValueType const &value)
{
if (m_map.find(key) != m_map.end())
{
return false;
}
else
{
char *copy = new char[strlen(key) + 1];
strcpy(copy, key);
try
{
return m_map.insert(std::make_pair(copy, value)).second;
}
catch (...)
{
delete copy;
throw;
}
}
}
~FastStringMap()
{
for (iterator iter = m_map.begin(); iter != m_map.end(); ++iter)
{
delete[] iter->first;
}
}
iterator find(char const *key)
{
return m_map.find(key);
}
const_iterator find(char const *key) const
{
return m_map.find(key);
}
// further operations
};
To be used like this:
FastStringMap<int> m;
m.insert("AAA", 1);
m.insert("BBB", 2);
m.insert("CCC", 3);
std::cout << m.find("AAA")->second;
Note that you can possibly make this more sophisticated by templatising also on the character type (for std::wstring support) or by providing "real" iterator classes (using Boost Iterator Facade).
And: If you remove an object from the map, I'll need to release both
the related object and the key, do I?
If you use std::string, no. If you use char const * and if the pointers point to memory allocated dynamically (as in my example), then yes.

Function that returns a pointer to const 2-d array (C++)

I'm an intermittent programmer and seem to have forgotten a lot of basics recently.
I've created a class SimPars to hold several two-dimensional arrays; the one shown below is demPMFs. I'm going to pass a pointer to an instance of SimPars to other classes, and I want these classes to be able to read the arrays using SimPars accessor functions. Speed and memory are important.
I know life is often simpler with vectors, but in this case, I'd really like to stick to arrays.
How do I write the accessor functions for the arrays? If I'm interested in the nth array index, how would I access it using the returned pointer? (Should I write a separate accessor function for a particular index of the array?) What's below is certainly wrong.
// SimPars.h
#ifndef SIMPARS_H
#define SIMPARS_H
#include "Parameters.h" // includes array size information
class SimPars {
public:
SimPars( void );
~SimPars( void );
const double [][ INIT_NUM_AGE_CATS ] get_demPMFs() const;
private:
double demPMFs[ NUM_SOCIODEM_FILES ][ INIT_NUM_AGE_CATS ];
};
#endif
// SimPars.cpp
SimPars::SimPars() {
demPMFs[ NUM_SOCIODEM_FILES ][ INIT_NUM_AGE_CATS ];
// ...code snipped--demPMFs gets initialized...
}
//...destructor snipped
const double [][ INIT_NUM_AGE_CATS ] SimPars::get_demPMFs( void ) const {
return demPMFs;
}
I would greatly appreciate some kind of explanation with proposed solutions.
Basically, you have three options: return the entire array by reference, return the first row by pointer, or return the entire array by pointer. Here is the implementation:
typedef double array_row[INIT_NUM_AGE_CATS];
typedef array_row array_t[NUM_SOCIODEM_FILES];
array_t demPMFs;
const array_t& return_array_by_reference() const
{
return demPMFs;
}
const array_row* return_first_row_by_pointer() const
{
return demPMFs;
}
const array_t* return_array_by_pointer() const
{
return &demPMFs;
}
And here are the use cases:
SimPars foo;
double a = foo.return_array_by_reference()[0][0];
double b = foo.return_first_row_by_pointer()[0][0];
double c = (*foo.return_array_by_pointer())[0][0];
How would I return just the nth row of the array?
Again, you have three choices:
const array_row& return_nth_row_by_reference(size_t row) const
{
return demPMFs[row];
}
const double* return_first_element_of_nth_row_by_pointer(size_t row) const
{
return demPMFs[row];
}
const array_row* return_nth_row_by_pointer(size_t row) const
{
return demPMFs + row;
}
const double (* get_demPMFs() const)[INIT_NUM_AGE_CATS];
Or, use typedef (but that doesn't seems cleaner...).
class SimPars {
typedef const double (*ConstDemPMFType)[INIT_NUM_AGE_CATS];
double demPMFs[NUM_SOCIODEM_FILES][INIT_NUM_AGE_CATS];
public:
ConstDemPMFType get_demPMFs() const;
};
Note that you can't return an array (g++ refuses the compile). But an array of array can be decayed to a pointer to array, so the latter is returned.
Logically speaking there is this question with a data member. Should users be allowed to modify it or not. If you want to give another class full access to the member, you don't necessarily need getter/setter, especially if you are the only user. You can just make the member public.
If your class would be better off controlling how users access the member, then you could use a getter only to enforce read only access. The simplest way to do this if you don't want to get all confused about the 2-dimensional arrays is to just have an inline function fetching the element for the user class:
const double& getElem( int x, int y ) const { return demPMF[x][y] }
It makes sense to do bounds checking here, but considering that you insist on using arrays, and if your profiler proves that you can't afford it, this function would just allow access to your array.
If you want further elaboration, post a comment...