I'm kind of confused with vectors in C++; this is my first time using them. I made a vector of strings, and I am trying to compare elements in that vector against a letter.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
/* Head ends here */
void displayPathtoPrincess(int n, vector <string> grid){
for(vector<string>::iterator it = grid.begin(); it != grid.end(); ++it) {
if(*it.strcompare('p') != 0)
cout << 'Princess found!';
}
}
/* Tail starts here */
int main() {
int m;
vector <string> grid;
cin >> m;
for(int i=0; i<m; i++) {
string s; cin >> s;
grid.push_back(s);
}
displayPathtoPrincess(m,grid);
return 0;
}
Why won't this work? Won't *it always be a string type?
Here is my error:
error: 'std::vector >::iterator' has no member named 'strcompare'
First, in this context, . binds tighter than *, so this
*it.strcompare('p')
is equivalent to
*(it.strcompare('p'))
so you should call something like
it->methodName(args)
Second, you need to call a method of std::string, presumably std::string::compare.
Note that if all you want to do is search for an entry equal to "p", then all you have to do is
auto it = std::find(grid.begin(), grid.end(), "p");
if (it != v.end()) std::cout << "Princess found!" << std::endl;
The class std::string is basic_string ( http://en.cppreference.com/w/cpp/string/basic_string ) and I do not think this class has a standard strcompare member function(Though some compilers do provide one).
I think you are trying to do something like:
if(*it == String("P"))
Which can more simply be written as:
if(*it == "P")
for an example: http://ideone.com/isa9Il
There is no strcompare in the Standard Library.
Perhaps you meant compare?
Also, yes *it will be a string -- but 'p' is not. That is a char. You need to either convert 'p' to a string (eg string s(1,'p')) or compare the first (or last) character in *it to 'p' (eg (*it)[0] == 'p' -- warning, unsafe as is)
Finally, others have already mentioned this, but *it.strcompare would not bind as (*it).strcompare, but rather as *(it.strcompare). Meaning, you are trying to call a method called strcompare on the iterator, rather than what the iterator refers to. Even if string had a method called strcompare (which it doesn't), your code still wouldn't compile.
Related
I am using std::find to check a string isn't in std::vector<std::vector<string>>
Error:
no match for 'operator==' (operand types are 'std::vector<std::__cxx11::basic_string<char> >' and 'const char [6]')
Isn't it the type doesn't match?
vector< vector< string>>data;
if(find(data.begin(), data.end(), "START") == data.end()){
printf("Missing \"START\"\n");
return true;`
The reason for the error message has been well explained in the other answer. I would like to provide a solution to the problem.
As you are trying to find, if any of the std::string element in the vector of vector matches to "START", you could use standard algorithm std::any_of in combination with a unary predicate which returns std::find(vec.cbegin(), vec.cend(), str) != vec.cend(); where vec is the each rows of the vector of vectors. See a demo here
#include <algorithm>
#include <string>
#include <iostream>
#include <vector>
bool isFound(const std::vector<std::vector<std::string>>& data, const std::string &str)
{
const auto found_in_vector = [&str](const std::vector<std::string> & vec)-> bool {
return std::find(vec.cbegin(), vec.cend(), str) != vec.cend(); // if found
};
if (std::any_of(data.cbegin(), data.cend(), found_in_vector))
{
std::cout << "Found\n";
return true;
}
std::cout << "Missing \""<< str << " \"\n";
return false;
}
int main()
{
std::vector<std::vector<std::string>> data;
std::vector<std::string> test{ "START","test" };
data.emplace_back(test);
std::cout << std::boolalpha << isFound(data, std::string{ "START" } );
}
Yes and no. The error is triggered, because you've got a "vector of vectors of strings", i.e. there's one dimension too much. Define data using std::vector<std::string> instead and it will work.
But why does the error talk about a missing operators?
When you use std::find(), it's typically implemented as a macro or templated function, which does the actual work, rather than a precompiled runtime function somewhere in a library. This allows the compiler full optimization based on the actual types of your parameters.
What it actually does - since your container is a class - is trying to find a special member function, std::vector<std::vector<std::string>>::operator==(const char*). It's not directly implemented this way, typically a template instead, but that's not important here. The important fact is it won't find any version of operator==() with an argument that is somehow able to accept the string passed, either directly or through conversion. Reason for this is that your vector contains vectors, so the only valid argument would be another vector of strings.
I've created a unordered_set of my own type of struct. I have an iterator to this set and would like to increment a member (count) of the struct that the iterator points to. However, the compiler complains with the following message:
main.cpp:61:18: error: increment of member ‘SentimentWord::count’ in read-only object
How can I fix this?
Here's my code:
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <string>
#include <unordered_set>
using namespace std;
struct SentimentWord {
string word;
int count;
};
//hash function and equality definition - needed to used unordered_set with type SentimentWord
struct SentimentWordHash {
size_t operator () (const SentimentWord &sw) const;
};
bool operator == (SentimentWord const &lhs, SentimentWord const &rhs);
int main(int argc, char **argv){
ifstream fin;
int totalWords = 0;
unordered_set<SentimentWord, SentimentWordHash> positiveWords;
unordered_set<SentimentWord, SentimentWordHash> negativeWords;
//needed for reading in sentiment words
string line;
SentimentWord temp;
temp.count = 0;
fin.open("positive_words.txt");
while(!fin.eof()){
getline(fin, line);
temp.word = line;
positiveWords.insert(temp);
}
fin.close();
//needed for reading in input file
unordered_set<SentimentWord, SentimentWordHash>::iterator iter;
fin.open("041.html");
while(!fin.eof()){
totalWords++;
fin >> line;
temp.word = line;
iter = positiveWords.find(temp);
if(iter != positiveWords.end()){
iter->count++;
}
}
for(iter = positiveWords.begin(); iter != positiveWords.end(); ++iter){
if(iter->count != 0){
cout << iter->word << endl;
}
}
return 0;
}
size_t SentimentWordHash::operator () (const SentimentWord &sw) const {
return hash<string>()(sw.word);
}
bool operator == (SentimentWord const &lhs, SentimentWord const &rhs){
if(lhs.word.compare(rhs.word) == 0){
return true;
}
return false;
}
Any help is greatly appreciated!
Elements in an unordered_set are, by definition, immutable:
In an unordered_set, the value of an element is at the same time its
key, that identifies it uniquely. Keys are immutable, therefore, the
elements in an unordered_set cannot be modified once in the container
- they can be inserted and removed, though.
I would vote that you use an unordered_map instead, using a string as the key and an int as the mapped value.
One solution (but a dirty hack) is to make your counter mutable, which means, that you permit to change it even on const objects.
struct SentimentWord {
string word;
mutable int count;
};
As I already said, this is a dirty hack, since it allows you to violate rules (you soften them). And rules have a reason. I'm not even sure if this works, since the definition of the unordered_set says that the values can't be modified once being inserted, and this also has a reason.
A nicer solution is to use a map which uses the word as a key and the counter as a value. Your code then doesn't have to use find but simply access the element using the subscript operator ("array access" operator) which directly returns a reference (not an iterator). On this reference, use the increment operator, like this:
std::unordered_map<std::string,int> positiveWords;
//...
positiveWords[word]++;
Then you don't need your struct at all, and of course also not your custom comparison operator overload.
Trick (just in case you need it): If you want to order a map by its value (if you need a statistical map with the most frequent words coming first), use a second (but ordered) map with reversed key and value. This will sort it by the original value, which is now the key. Iterate it in reverse order to start with the most frequent words (or construct it with std::greater<int> as the comparison operator, provided as the third template parameter).
std::unordered_set is unhappy because it's worried you will change the object in such a way it is the same as another object, which would violate the set. ISTM you really want a map from string to int (not a set at all), and the iterator will let you change the returned value, if not the key.
i'm trying to use algorithm lib & vector lib to first copy a set of numbers from an array into a vector then printing it using iteration, where is the problem of my code?
and one thing is that i chose 2 way to do this iteration first using vec.begin() ; vec.end() method & the other one is for (i = 0 ; i < vec.capacity() ; i++)
both facing errors.
what should i do?
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int intArray[] = {5,6,8,3,40,36,98,29,75};
vector<int> vecList(9);
//vector<int>::iterator it;
copy (intArray, intArray+9,vecList);
//for(it = vecList.begin() ; it != vecList.end() ; it++)
for (int it = 0 ; it < vecList.capacity() ; it++)
{
cout<<*it<<endl;
}
system("pause");
return 0;
}
There are several improvements possible.
You confuse iterators with indices. An iterator it is a glorified pointer into the vector, that you need to derefence by typing *it. An index i is an offset from the beginning of the vector and saying vecList[i] will give you that element.
The initialization of the vector is best done using initializer lists (C++11), rather than reading from an array.
You need to loop to vecList.size(). The capacity of the vector is the size of the allocated storage space for the elements of the vector container. Looping is best done with a ranged-for loop as shown by Kerrek SB, or a std::for_each + a lambda expression, or a regular for loop as you did. In that case however, it's best to get into the habit of doing it != vecList.end() (instead of using <) and doing ++it instead of it++.
Note that I also used auto to avoid writing the explicit iterator type. It's also a good habit to get into using auto wherever you can.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
// initialize vector with a list of elements
vector<int> vecList {5,6,8,3,40,36,98,29,75};
// loop from begin() to end() of vector, doing ++it instead of it++
for (auto it = vecList.begin(); it != vecList.end(); ++it)
{
cout<<*it<<endl;
}
// the pause command is better done by setting a breakpoint in a debugger
return 0;
}
Output on Ideone (this uses the g++ 4.5.1 compiler, it's best to upgrade to at least that version to take advantage of C++11 features).
The problem is that you're confusing indexes and iterators.
w/ index:
for (int i = 0 ; i < vecList.size() ; it++)
{
cout<<vecList[i]<<endl;
}
w/ iterators
for (std::vector<int>::const_iterator it = vecList.begin() ; i != vecList.end() ; it++)
{
cout<<*it<<endl;
}
A. you need to iterate on vecList.size() not vecList.capacity() which mean how much memory the vector is reserving for himself (not how much of it is in use).
B. you tried to use the integer index it as an iterator with the call to *it, you should check Luchian Grigore answer for the right way to do it.
This isn't an answer, but I wanted to show how modern C++ allows you to do away with lots of the brittle dependencies on details:
int intArray[] = {5,6,8,3,40,36,98,29,75};
std::vector<int> vecList(std::begin(intArray), std::end(intArray));
for (int i : vecList) { std::cout << i << std::endl; }
Using iterators and algorithms idiomatically, you can often remove any explicit mention of details such as lengths of arrays, thus making your code more robust.
Typo mistake use : copy (intArray, intArray+9,vecList.begin());
so,
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
int main()
{
int intArray[] = {5,6,8,3,40,36,98,29,75};
vector<int> vecList(9);
vector<int>:: iterator it;
copy (intArray, intArray+9,vecList.begin());
for (it=vecList.begin();it!=vecList.end(); it++)
{
cout<<*it<<endl;
}
system("pause");
return 0;
}
If I use a default constructor for an iterator, how to check if it was assigned later on?
For pointers, I could do this :
int *p = NULL;
/// some code
if ( NULL == p ) {
// do stuff
}
How do I do the above for iterators?
Is it possible at all?
#include <iostream>
#include <list>
int main ()
{
std::list<int>::iterator it;
if ( NULL == it ) // this fails
{
std::cout<<"do stuff" << std::endl;
}
}
I managed to find this in the current standard (c++03 ). 24.1 p 5 tells :
Just as a regular pointer to an array guarantees that there is a
pointer value pointing past the last element of the array, so for any
iterator type there is an iterator value that points past the last
element of a corresponding container. These values are called
past-the-end values. Values of an iterator i for which the expression
*i is defined are called dereferenceable. The library never assumes
that past-the-end values are dereferenceable. Iterators can also have
singular values that are not associated with any container. [Example:
After the declaration of an uninitialized pointer x (as with int* x;),
x must always be assumed to have a singular value of a pointer. ]
Results of most expressions are undefined for singular values; the
only exception is an assignment of a non-singular value to an iterator
that holds a singular value. In this case the singular value is
overwritten the same way as any other value. Dereferenceable values
are always non- singular.
(Emphasis mine)
So the answer is : no, it is not possible.
Most iterators don't have any global special values in the same way that all pointers can be NULL. Typically, though, you'll be working with specific containers, and if you keep one iterator per container, then you can use end() as the sentinel value:
std::list<int> mylist;
std::list<int>::iterator it = mylist.end();
/* do stuff */
if (it == mylist.end()) { ... }
I'm not sure if insertion/deletion invalidates the end() iterator, though, so if you're planning on modifying your container, maybe save a copy of the original end, too:
std::list<int>::iterator end = mylist.end(), it = end;
if (it == end) { ... }
Though again I'm actually not sure if it's well-defined to compare two invalid iterators (in the event that the two do get invalidated).
This question has already been treated in Stackoverflow. The quintessence is that the default constructor initializes an iterator to a singular value, and the only addmissible operation on it is to assign it another iterator value. In particular it is not possible to query the value of such unitialized iterator. Therefore it is a good programming practice to initialize the iterator to a specific value of a specific container, which then can be tested for.
Since there is no default value for iterators (like there is NULL for pointers), in situation where i need a common default value for a Object::iterator (before any actual Object has been created) I create a dummy static variable and use its ::end() as the default.
Update : This only works for Release, because in DEBUG (or with _HAS_ITERATOR_DEBUGGING=1) comparison operators check if both iterators point to the same object/container.
For example for vector<int> I would do :
class A
{
public :
A() : myIterator1(dummyVector.end()), myIterator2(dummyVector.end()) {}
// needed iterators
vector<int>::iterator myIterator1;
vector<int>::iterator myIterator2;
static const vector<int> dummyVector;
}
#define IT_NULL A::dummyObject.end()
void maint() {
A::dummyObject = vector<int>(); // initialize the Null iterator
A a;
if(a.myIterator1 == IT_NULL) cout << "Iterator not yet initialized";
}
You can't. ll you can do is compare against list end
it != mylist.end();
In C++, uninitialized local variables can have any value i.e it contains simply garbage. That implies, you cannot check it against some well-defined value, to determine if the variable is uninitialized or not.
Not only that if the variable is not initialized and you write this:
if ( NULL == it ) // this fails
then it invokes undefined behavior.
Maybe you should always assign a predefined value, like NULL, after creating the iterator. Later you can easily check against NULL.
This will make your code more portable, as you will not depend on what starting values the uninitialized variables take at the beginning.
if(std::list<int>::iterator() == it)
But I suspect... may it's possible, that a valid iterator could pass the comparison.
Better to avoid these situations. If it's impossible store the iterator by a pointer.
std::auto_ptr<std::list<int>::iterator> it;
The best way to do this I can think of is something like
#include <utility>
#include <map>
#include <typeinfo>
#include <string>
namespace nulliterators {
typedef std::map<std::string, void*> nullcntT;
nullcntT nullcontainers;
template<class containerT>
typename containerT::iterator iterator() {
containerT* newcnt = new containerT();
std::string cnttypename = typeid(*newcnt).name();
nullcntT::iterator i = nullcontainers.find(cnttypename);
if (i==nullcontainers.end()) {
nullcontainers.insert(make_pair(cnttypename, newcnt));
return newcnt->end();
}else{
delete newcnt;
return (static_cast<containerT*>(i->second))->end();
}
}
}
template<class containerT>
typename containerT::iterator nulliterator() { return nulliterators::iterator<containerT>(); }
#include <list>
#include <iostream>
int main(){
std::list<int>::iterator nullinitized = nulliterator< std::list<int> >();
std::list<int> somelist;
std::list<int>::iterator initialized = somelist.end();
if (nullinitized == nulliterator< std::list<int> >())
std::cout << "nullinitized == nulliterator< std::list<int> >()\n"; //true
else
std::cout << "nullinitized != nulliterator< std::list<int> >()\n";
if (initialized == nulliterator< std::list<int> >())
std::cout << "initialized == nulliterator< std::list<int> >()\n";
else
std::cout << "initialized != nulliterator< std::list<int> >()\n"; //true
return 0;
}
but it's not exactly a safe solution (because it relies on the non-const global containers in nullcontainers).
As far as I know you must always initialize your iterators and the easiest way is to make them equal to 'container'.end()
In certain cases it looks like working, we had some problems with code that worked with VC6 and stopped working with VC2010. Look at this example compiled with g++ where it works for the vector but not for the map:
# Test iterator init, compile with: g++ test-iterator.cpp -o test-iterator
#include <iostream>
#include <vector>
#include <map>
int main()
{
std::vector<int> vec;
std::vector<int>::iterator it;
if (it != vec.end())
{
std::cout << "vector inside!" << std::endl;
}
else
{
std::cout << "vector outside!" << std::endl;
}
std::map<int, int> mp;
std::map<int, int>::iterator itMap;
if (itMap != mp.end())
{
std::cout << "map inside!" << std::endl;
}
else
{
std::cout << "map outside!" << std::endl;
}
return 0;
}
I used the following solution:
const MyList_t::const_iterator NullIterator(NULL);
const_iterator MyList_t::MyIterator;
Then a check is possible:
if (NullIterator != MyIterator) {}
I have three questions regarding a homework assignment for C++. The goal was to create a simple palindrome method. Here is my template for that:
#ifndef PALINDROME_H
#define PALINDROME_H
#include <vector>
#include <iostream>
#include <cmath>
template <class T>
static bool palindrome(const std::vector<T> &input)
{
std::vector<T>::const_iterator it = input.begin();
std::vector<T>::const_reverse_iterator rit = input.rbegin();
for (int i = 0; i < input.size()/2; i++, it++, rit++)
{
if (!(*it == *rit)) {
return false;
}
}
return true;
}
template <class T>
static void showVector(const std::vector<T> &input)
{
for (std::vector<T>::const_iterator it = input.begin(); it != input.end(); it++) {
std::cout << *it << " ";
}
}
#endif
Regarding the above code, can you have more than one iterator declared in the first part of the for loop? I tried defining both the "it" and "rit" in the palindrome() method, and I kept on getting an error about needing a "," before rit. But when I cut and paste outside the for loop, no errors from the compiler. (I'm using VS 2008).
Second question, I pretty much just brain farted on this one. But is the way I have my return statements in the palindrome() method ok? In my head, I think it works like, once the *it and *rit do not equal each other, then the function returns false, and the method exits at this point. Otherwise if it goes all the way through the for loop, then it returns true at the end. I totally brain farted on how return statements work in if blocks and I tried looking up a good example in my book and I couldn't find one.
Finally, I get this warnings:
\palindrome.h(14) : warning C4018: '<' : signed/unsigned mismatch
Now is that because I run my for loop until (i < input.size()/2) and the compiler is telling me that input can be negative? Thanks!
Are iterators a requirement of the homework assignment? This task can be reduced to a call to std::equal:
template <class T>
bool palindrome(const std::vector<T> &input)
{
return equal(input.begin(), input.begin()+input.size()/2, input.rbegin());
}
can you have more than one iterator declared in the first part of the for loop?
Yes, but they both have to be of the same type, so you can't declare both a const_iterator and a const_reverse_iterator.
is the way I have my return statements in the palindrome() method ok?
Yes, though why not just compare *it != *rit?
palindrome.h(14) : warning C4018: '<' : signed/unsigned mismatch
i is signed; std::vector::size() returns an unsigned value. If i was unsigned, you would not get this warning.
As a suggestion, though: it might be simpler to use two forward iterators. Initialize one to .begin() and the other to .end() - 1. You can then increment the first and decrement the second and your loop test simply becomes it1 < it2. Something like the following (completely untested) for-loop:
for (iterator it1(v.begin()), it2(v.end() - 1); it1 < it2; ++it1, --it2)
This way you no longer need the separate i counter and comparisons; everything is done with iterators.
The for loop works for me when iterators are of the same type, I haven't figured out other way yet - apart from initializing them outside like what you did:
typedef vector<char>::const_iterator IT;
for (IT it(vchars.begin()), end(vchars.end()); it != end; ++it)
{
cout << *it << endl;
}
Regarding the return statement, your reasoning is correct but you start with those 2 iterators not being the same, one starts from front the other from the end. So on the first iteration they are not equal and you return false - I believe.
And last, the warning points to the fact that size() returns unsigned type (size can't be negative) but you are compare with signed value i, which in most cases is not a real problem - but to be neat you can declare your i as unsigned.
This will fix that:
for (unsigned int i = 0; i < input.size()/2; ...)