#include <vector>
int main()
{
typedef const std::vector<const int> set_t;
set_t Low = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18};
return 0;
}
When compiling the above code I got trillion of errors from STL headers.
What I want to do here is to initialize a vector and ensure that values can not be changed at some point later and also to make sure that no new values can be added.
This vector should be created once with initial values and not changed in any way.
What's wrong here?
This is also a const vector, and it will let your code compile.
typedef const std::vector<int> set_t;
Making the std::vector alone const will expose only the non-modifying interface. Your ints will not change.
Related
I've seen code that uses a const std::vector, however can't see why it wouldn't make more sense to simply use an std::array instead.
The values for the vector seem to be initialized at compile-time.
What is the benefit of a const std::vector?
Edit: The vector was not big, only a couple of strings, however I see that this may be one advantage.
const std::vector lets you have a "fixed sized array" whose size you only know at run time but still allows you to have all the benefits of a standard container. If you used a raw/smart pointer in your code you will need to manually pass the size of the array that it points to into the function(s) that need to know the size of the array.
The std::vector could be used with a large list of data, because it could use Dynamic Allocated Array to store values and before C++20 it's doesn't have a constexpr constructor. But std::array uses a raw C-Array and it could be used at compile time with the stack size restricted list of data. So:
std::array const is good for:
Where your data size is less than the stack size.
Where data locality is important.
You want your list at the compile time (before C++20).
std::vector const is good for:
Where your data size is large than the stack size.
It's quite common to see C++ code that expects references to vectors, sometimes const, something like this:
auto do_sum(std::vector<int> const& numbers) -> int {
return std::accumulate(numbers.begin(), numbers.end(), 0);
}
Even though the good intentions are not about not copying memory, this code require the caller to allocate a std::vector, even though the amount of value and the actual values might be known at compile time.
This might be fixed by using a span instead:
auto do_sum(std::span<int const> numbers) -> int {
return std::accumulate(numbers.begin(), numbers.end(), 0);
}
Now this code don't require the users to allocate a vector for the array, and might use std::array, or plain C arrays.
Also, sometimes you don't know what are the numbers of element the array can have, and might be determined at runtime. Consider this:
auto create_vector() -> std::vector<int> {
auto vec = std::vector<int>{};
if (/* runtime condition */) {
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
} else {
vec.push_back(4);
vec.push_back(5);
}
return vec;
}
int main() {
std::vector<int> const vec = create_vector();
}
As you can see here, as the vector is moved from scope to scope, the const-ness changes and is expressing the intent of the developer to only make it mutable in some initializing scopes.
Because the std::array needs you to specify the size as part of the type. By using std::vector the compiler can work that out for your dynamically.
This matters in maintenance situations as it prevents errors. You only add/remove a string from the initializer of the object and the vector will have the correct size automatically. If you use an array you need to add/remove the string and change the type of the array.
const std::vector<std::string> dataV = { "A", "B", "C" };
const std::array<std::string, 3> dataA = { "A", "B", "C" };
If I now modify these to only have two values.
// The vector will auto resize
const std::vector<std::string> dataV = { "A", "B"};
// This will still be of size three.
// This is not usually what you want.
const std::array<std::string, 3> dataA = { "A", "B"};
// The person modifying the code has to manually spot that and
// change the type to explicitly have two member array. Note
// It may not be as obvious as you think as the type may
// be hidden with a type alias of some description
using DataStore = std::array<std::string, 3>;
/// Lots of code:
DataStore dataA = { "A", "B"}; // Would you have spotted.
I am following this example to make an adjacency list. However it seems like the vector size cannot be dynamic.
Visual studio throws an error
expression did not evaluate to a constant
on this line
vector<int> adj[V];
The strange thing is that the same exact code works correctly on codeblocks IDE.
I've tried replacing the above line with vector<int> adj; but then I cannot send the vector as a parameter to addEdge(adj, 0, 1); as it throws another error about pointers which I also don't know how to correct.
What could I do to dynamically create my vector?
C++ - How to create a dynamic vector
You don't need to do that for this example. But if you did need it, you could use std::make_unique.
The linked example program is ill-formed. I recommend to not try to learn from that. The issue that you encountered is that they use a non-const size for an array. But the size of an array must be compile time constant in C++. Simple fix is to declare the variable type as const:
const int V = 5;
I've tried replacing the above line with vector<int> adj;
You can't just replace an array of vectors with a single vector and expect the program to work without making other changes.
I need the size to be dynamic as it will only be known at compile time.
Assuming you meant to say that the size will only be known at runtime, the solution is to use a vector of vectors.
As written by eerorika, the example code isn't a good one, and you should avoid using raw arrays like that. An array in C/C++ is of static size, each vector in this array is dynamic, but the entire array is not!
There are two approaches for such a question. Either use adjacency lists (which is more common):
#include <vector>
#include <stdint.h>
class Vertix
{
public:
Vertix(uint64_t id_) : id(id_) {}
uint64_t get_id() const { return id; }
void add_adj_vertix(uint64_t id) { adj_vertices.push_back(id); }
const std::vector<uint64_t>& get_adj_vertices() const { return adj_vertices; }
private:
uint64_t id;
std::vector<uint64_t> adj_vertices;
};
class Graph
{
public:
void add_vertix(uint64_t id)
{
vertices[id] = Vertix(id);
}
void add_edge(uint64_t v_id, uint64_t u_id)
{
edges.emplace_back(u_id, v_id);
vertices[u_id].add_adj_vertix(v_id);
}
private:
std::vector<Vertix> vertices;
std::vector<std::pair<uint64_t, uint64_t>> edges;
};
or use double vector to represent the edges matrix:
std::vector<std::vector<uint64_t>> edges;
But it isn't a real matrix, and you cannot check if (u, v) is in the graph in O(1), which misses the point of having adjacency matrix. Assuming you know the size of Graph on compile time, you should write something like:
#include <array>
#include <stdint.h>
template <size_t V>
using AdjacencyMatrix = std::array<std::array<bool, V>, V>;
template <size_t V>
void add_edge(AdjacencyMatrix<V>& adj_matrix, uint64_t u, uint64_t v)
{
if (u < V && v < V)
{
adj_matrix[u][v] = true;
}
else
{
// error handling
}
}
Then you can use AdjacencyMatrix<5> instead of what they were using on that example, in O(1) time, and although it has static size, it does work as intended.
There’s no need to use C-style arrays in modern C++. Their equivalent is std::array, taking the size as a template parameter. Obviously that size can’t be a runtime variable: template parameters can be types or constant expressions. The compiler error reflects this: std::array is a zero cost wrapper over an internal, raw “C” array.
If the array is always small, you may wish to use a fixed-maximum-size array, such as provided by boost. You get all performance benefits of fixed size arrays and can still store down to zero items in it.
There are other solutions:
If all vectors have the same size, make a wrapper that takes two indices, and uses N*i1+i2 as the index to an underlying std::vector.
If the vectors have different sizes, use a vector of vectors: std::vector>. If there are lots of vectors and you often add and remove them, you may look into using a std::list of vectors.
I want to build a variable like vector(map(pair(struct))) and use it to store information in C++, I try to use following code:
struct st_Base
{
char Type[2];
double Price;
queue<double> Samples;
};
vector< map< string, pair< st_Base, st_Base >* >* > gv_combo;
string str_source = "test123";
gv_combo.push_back(new map<str_source, new pair<st_Base, st_Base>>);
But when I run the program, it always show me lots of errors. Can anyone told me the right way to build it, place data in it, and read it?
Consider not using dynamic allocation via new keyword (Manual memory management is prone to errors). If your memory needs to be allocated dynamically use unique pointer std::unique_ptr.
What you are esentially creating is a container holding a pointer to container that is holding a pair of values (string (key), and pointer to pair of structs (value)).
#include <vector>
#include <map>
#include <utility>
#include <memory>
#include <iostream>
struct st_Base { int foo; };
int main()
{
typedef std::pair< st_Base, st_Base> weird_pair;
std::vector<std::map<std::string, weird_pair>> gv_combo;
string str_source = "test123";
weird_pair pair = make_pair(st_Base{ 10 }, st_Base{ 11 });
gv_combo.push_back(std::map<std::string, weird_pair>());
gv_combo.at(0).insert(std::pair<std::string, weird_pair>(str_source, pair));
std::cout << gv_combo.at(0).at("test123").second.foo;
return 1;
}
But this example is extremly unreadable (at least for me). Access to members of structs is not straightforwarwd (needs to call at() to localize element in map, then use first/second to access apropriate st_Base which results in ever increasing chain of calls.
Adding unique_ptr would result in even longer chain that would put my brain on a verge of scrapping the entire code after working with it for any period of time.
Notes to OP:
-read documentation carefully, it's your friend
-allocate with keyword new only when you really have to (eg. obscure framework pre c++11)
-typedefs save lifes
-pointers can get out of hand quickly if you don't wrap them into nice structure
-objects can use initializer lists {} to give them data during construction of the object. it's worth noting that C and C++ versions {} are not exchangable ( st_Base{.foo=10} is legal in C, but illegal in c++ )
This seems to be what you are trying to achieve:
struct st_Base {
char Type[2];
double Price;
std::queue<double> Samples;
};
std::vector<std::map<std::string, std::pair<st_Base, st_Base>>> gv_combo;
string str_source = "test123";
std::map<std::string, std::pair<st_Base, st_Base>> my_map;
my_map[str_source] = std::make_pair(st_Base(...), st_Base(...)); // instert pair of objects here
gv_combo.push_back(my_map);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why isn't the [] operator const for STL maps?
I've boiled this down to (what I think is) its simplest form:
#include <iostream>
#include <map>
#include <vector>
class NumberHolder
{
public:
NumberHolder( const std::string aKey, const double aNumber );
void printSmallestMappedNumber( const unsigned int theIndex ) const;
private:
std::vector< std::map< std::string, double> > theNamedNumberMapVector;
};
NumberHolder::NumberHolder( const std::string key, const double aNumber )
{
std::map<std::string, double> aTempMap;
aTempMap[key] = aNumber;
theNamedNumberMapVector.push_back(aTempMap);
}
void NumberHolder::printSmallestMappedNumber( const unsigned int theIndex ) const
{
std::map<std::string, double>& aSpecificMap = theNamedNumberMapVector[theIndex];
std::cout << aSpecificMap["min"] << std::endl;
}
int main(int argc, char* argv[])
{
NumberHolder aTaggedNumberHolder("min", 13);
aTaggedNumberHolder.printSmallestMappedNumber( 0 );
return 0;
}
I have a vector full of maps, and each map is full of (string) "tagged" numbers. I'm trying to keep as tight of control over access to the visibility/mutability of the variables involved.
Anyhow, the compiler fails with this error
Binding of reference to type 'std::map' to a value of type 'const std::map, double, std::less >, std::allocator, double> > >' drops qualifiers
My first (underbaked) attempt was making the map const..., as I'm not modifying the map, only retrieving a value from it:
const std::map<std::string, double>& aSpecificMap = theNamedNumberMapVector[theIndex];
Which then presents me with this admittedly shorter, but actually a bit more confusering error:
No viable overloaded operator[] for type 'const std::map<std::string, double>'
On the following line instead:
std::cout << aSpecificMap["min"] << std::endl;
However, perhaps because I've been trying to untangle this for a bit, my solution seems to be awfully, awfully crufty:
std::map<std::string, double>& aSpecificMap = const_cast<std::map<std::string, double>&>(theNamedNumberMapVector[theIndex]);
const_casting away the [const derp] qualifier works around my problem, but I would really like to have a clear understanding of exactly what's going on. I'm guessing that the compiler is disgruntled about my access to the map (in my second attempt, above) and believes that I will use & abuse my access to the map's contents. I'd really like / need to be able to explain stuff like this to other people, as well as trying not to abuse the language and ultimately end up on The Daily WTF, because, you know, shame and stuff.
If you look at the declaration for map's operator[], you will see that it is not const qualified, which is why it cannot be called on a const std::map<std::string, double>. The reason it is not const is because if the key does not exist in the map, it creates it. You should instead use find or at to get the element.
map<>::operator[] creates elements in the map if they don't already exist, which is why it's not allowed on a const object. You should use find().
(Some of the linked-at-right questions already answer this: e.g. Why isn't the [] operator const for STL maps? - I'll vote to close this as a duplicate)
I have a function which creates an array of Maps:
map<string, int> *pMap
And a function which writes maps to the array:
int iAddMap(map<string, int> mapToAdd, map<string, int> *m, int i)
{
m = &(pMap[i]);
memcpy(m, mapToAdd, sizeof(map<string, int>));
}
And a function to get maps from the array
map<string, int>& getMap(int i)
{
return pMap[i];
}
I can write maps to the array without any issue, but every get call results in a seg fault:
int val;
// val defined after this
map<string, int> * pGetMap = &(getMap(val));
Any suggestions on why this is happening?
You cannot use memcpy() to copy objects like maps, or indeed any other kind of C++ container - you need to use assignment, which takes into account the map's underlying structure and se,mantics. And you should be using a vector <map>, as you actually seem to want a copy rather than a pointer.
Never ever use memcpy for copying an object of a map (or whatever class, for that matter) - use assignment or copy constructor instead. memcpy is a C function, which has no idea of the internal structure of a C++ object, so it is almost guaranteed to mess things up.
Also you would better use an std::vector<map<string, int> > instead of an array:
std::vector<map<string, int> > maps;
void addMap(const map<string, int>& mapToAdd, int i)
{
maps[i] = mapToAdd;
}
map<string, int>& getMap(int i)
{
return maps[i];
}
Note: addMap does not return anything in your example code, so I changed its return type to void. Also I pass mapToAdd as const reference rather than by value.
This seems like an unholy mix of C and C++ programming, begin with changing:
memcpy(m, mapToAdd, sizeof(map<string, int>));
to
*m = *mapToAdd;
Also in the function
int iAddMap(map<string, int> mapToAdd, map<string, int> *m, int i)
What is the purpose of m? Any modifications to m won't be seen outside of this function.