3

I am wondering, if anyone could explain to me the second argument in the vector.insert() method:

iterator insert (iterator position, const value_type& val);

For example, I have a vector of type wstring and I would like to insert a wstring at a given position. I have figured out how to set the position using an iterator:

wstring word = "test";
int insertion_pos = 3;
iterator it = words.begin();
words.insert( it + insertion_pos, word );

But what about that second argument? How can I pass a wstring object to the insert() method? Thanks a lot.

Cheers,

Martin

Full example:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <wchar.h>
#include <vector>

using namespace std;

int main(void) {
    // Initialize the vecor with three words.
    vector<wstring> words;
    wstring word1 = "FirstWord"; // Error msg: no viable conversion from 'const char     [10]' to 'wstring' (aka 
                             //            'basic_string<wchar_t>')
    wstring word2 = "SecondWord"; // same here
    wstring word3 = "ThirdWord"; // same here

    words.push_back(word1);
    words.push_back(word2);
    words.push_back(word3);

    // Now try to insert a new word at position 2 (i.e. between "SecondWord "and "ThirdWord"
    int position = 2;
    wstring word4 = "InsertThis"; // same error as above
    iterator it = words.begin(); // Error: use of class template iterator requires template 
                             //      arguments
    words.insert( it + position, word4 ); 
//  Invalid arguments ' Candidates are:     __gnu_cxx::__normal_iterator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>> 
//   *,std::vector<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>,std::allocator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>>>> 
//   insert(__gnu_cxx::__normal_iterator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>> 
//   *,std::vector<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>,std::allocator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>>>>, 
//   const std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>> &) void 
//   insert(__gnu_cxx::__normal_iterator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>> 
//   *,std::vector<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>,std::allocator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>>>>,     
//   unsigned long int, const std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>> &) void 
//   insert(__gnu_cxx::__normal_iterator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>> 
//   *,std::vector<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>,std::allocator<std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>>>>, 
//   #10000, #10000) '

    return EXIT_SUCCESS;
}
marw
  • 403
  • 2
  • 8
  • 17

1 Answers1

6

Thanks for the clear example of the issue. Here is a modified version with some comments about changes. It compiles for me using clang on Mac OS X.

One change is the "L" in front of the string literal. This is an indicator that the string literal to follow is of type wchar_t. See also this.

Wide character/unicode/utf support is something I would add only if it's needed in the problem you're trying to solve.

// #include <stdio.h>   prefer "cstdio" to stdio.h; not used in example                                                                                                                                 
// #include <stdlib.h>  same                                                                                                                                                                            
#include <iostream>
#include <string>
// #include <wchar.h>  not used in example                                                                                                                                                              
#include <vector>

using namespace std;

// simplify to main()
int main() {
  // Initialize the vecor with three words.                                                                                                                                                             
  vector<wstring> words;
  wstring word1(L"FirstWord"); // Use Constructor, no assignment operator=                                                                                                                              
  wstring word2(L"SecondWord");
  wstring word3(L"ThirdWord");

  words.push_back(word1);
  words.push_back(word2);
  words.push_back(word3);

  int position = 2;
  wstring word4(L"InsertThis");
  // iterator depends on type of container                                                                                                    
  vector<wstring>::iterator it = words.begin();                                                                                                                                                         
  words.insert( it + position, word4 );

  for (const std::wstring& w : words)
    std::wcout << w << " ";
  std::wcout << std::endl;

  return EXIT_SUCCESS;
}

Understanding the insert call

The prototype for the vector's insert member function is:

  iterator insert( iterator pos, const T& value );

where T is the type you give as a template parameter, i.e. std::wstring in this case.

Iterators have operator+ overloaded, with the following semantics: iterator it + integer 2 returns a new iterator with a position 2 "increments" past the iterator it.

  words.insert( it + position, word4 );

Suggestion

One thing to be careful about it how you determine an inerstion position.

I think it would be better practice (more maintainable) to use an iterator to "walk along" the vector, rather than using iterator+offset. If you're not very comfortable with iterators, this would be a chance to learn how to use them.

This would avoid a potential situation, discussed in a previous version of this answer, where you accidentally offset your iterator past the end of the vector, leading to a segmentation violation.

Community
  • 1
  • 1
NicholasM
  • 4,557
  • 1
  • 20
  • 47
  • Thanks a lot for the detailed answer, Nicholas. You are right, of course: I should have been more precise as to where the problem is. The thing is that the line with the insert() statement doesn't even compile for me. I get an "Invalid arguments" error in Eclipse. In case it makes a difference, I am on Mac OS X 10.8.4 with Eclipse Kepler and project is using the Mac OS GCC toolchain. – marw Nov 03 '13 at 09:08
  • Could you please post a [minimal, compilable example](http://meta.stackexchange.com/questions/22754/sscce-how-to-provide-examples-for-programming-questions) that leads to this problem? Or at least, an example that you would expect to compile if the issue were resolved? I'm not familiar with wstring, but it sounds like your definition of `words` (and its value type) may not be compatible with your definition of `word` that you are trying to insert (mixing string and wstring?). Finally, if you could print the relevant lines of the compiler message, that would help. – NicholasM Nov 03 '13 at 09:35
  • Well, the following doesn't compile and if it were to compile, I wouldn't have any problems. But it should help illustrate the issues -> see edited question above. – marw Nov 03 '13 at 10:51
  • I seem to have found a solution to the wstring initialization problem: The following post describes an explicit conversion method. http://stackoverflow.com/questions/10737644/convert-const-char-to-wstring. Coming from the Java world, it seems a bit crazy to me that one has to go through this just to initialize string, but whatever. – marw Nov 03 '13 at 16:48
  • No argument here. :-) If you could mark this as "answered" if it solves your compilation problem, that would be appreciated. – NicholasM Nov 03 '13 at 17:16
  • Well, the original question still remains: how can I use the insert() method to actually insert a wstring into the vector? I am still getting the "Invalid arguments" error and can't compile the code. – marw Nov 03 '13 at 18:23
  • Did you change the declaration of `it`? I have `vector::iterator it = words.begin();` in my code example. The example I posted compiles for me. – NicholasM Nov 03 '13 at 18:32
  • Brilliant, that was it! Thanks so much, Nicholas. So, in conclusion, when using an iterator it needs to be derived from the typed class that it is meant to iterate over. – marw Nov 03 '13 at 19:35
  • Essentially, yes. Since "derived" has a very special meaning, it's fair to say that the iterator's type corresponds to the container's type, and that iterator type is provided by the container ( in this case, `std::vector::iterator`). – NicholasM Nov 03 '13 at 19:43