ostream, copy function printing string address, instead of string contents - c++

This prints the address for my string, but not its' contents,
#include <memory>
#include <string>
#include <list>
#include <iostream>
#include <iterator>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
unique_ptr<list<shared_ptr<string>>> upList (new list<shared_ptr<string>>);
shared_ptr<string> spNation (new string ("India"));
upList->push_back (spNation);
copy (upList->begin(), upList->end(), ostream_iterator<shared_ptr<string>> (cout, "\n "));
return 0;
}
My questions are:
What ostream_iterator<shared_ptr<string>> is taking shared_ptr or strings as its' prime object.
How to print actual string contents (i.e. India) using this approach.
Is this approach is preferable over traditional for loop to print all node contents.

What ostream_iterator<shared_ptr<string>> is taking shared_ptr or strings as its' prime object.
You've instantiated ostream_iterator for shared_ptr<string>, so that is what it will attempt to output.
How to print actual string contents (i.e. India) using this approach.
If you really want to use shared pointers for some reason, then you can't use copy since that won't undo the extra level of indirection. Either use a plain loop, or get rid of the unnecessary indirection:
list<string> list;
list.push_back("India");
copy(list.begin(), list.end(), ostream_iterator<string>(cout, "\n "));
Of course, it doesn't look as exciting without all the arrows, templates, new-expressions and pseudohungarian warts, but anyone trying to maintain the code won't thank you for adding such embellishments.
Is this approach is preferable over traditional for loop to print all node contents
It's preferable when it makes the code simpler. When it doesn't, it isn't.

Firstly: why you use shared_ptr<string> instead of string here? You shouln't do this.
1)
shared_ptr<string>
2) Use std::for_each with lambda (or range-based for loop)
for_each(upList->begin(), upList->end(), [](const shared_ptr<string>& p)
{
cout << *p << endl;
});
or
for (const auto& p : upList)
{
std::cout << *p << std::endl;
}

Related

How to shuffle an array in C++?

I have an array:
names[4]={john,david,jack,harry};
and i want to do it randomly shuffle, like:
names[4]={jack,david,john,harry};
I tried to use this but it just shuffled the letters of the first word in the array:
random_shuffle(names->begin(), names->end());
Here is the full code, it reads names from a .txt file and puts in an array:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
ifstream readName("names.txt");
string names[197];
int i = 0;
for (string line; getline(readName, line); ){
readName >> names[i];
i++;
}
readName.close();
random_shuffle(names->begin(), names->end());
for (int i = 0; i < 197; i++) {
cout << names[i] << endl;
}
return 0;
}
I tried few other things from different people but I couldn't manage to work it.. Anything helps, thank you!
Here's your code with what I felt were the smallest amount of changes. One could argue that I didn't need to change your first for loop as much, but I figure that if you have the prescience to know how many names you're reading, you might as well use the knowledge.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator> // std::begin(), std::end(); required for C-arrays
#include <random> // std::mt19937; needed to feed std::shuffle()
#include <string>
// using namespace std; // BAD PRACTICE
int main() {
constexpr int size = 4; // Give your magic number a name; only need to change
// a single location
std::ifstream readName("names.txt");
if (!readName) { // Always check that you successfully opened the file.
std::cerr << "Error opening file.\n";
return 1;
}
std::string names[size];
// int i = 0;
for (int i = 0; i < size; ++i) { // Retool the loop entirely
std::getline(readName, names[i]);
}
readName.close();
// This is a fragile solution. It's only working because the array is in
// scope
std::shuffle(std::begin(names), std::end(names),
std::mt19937{std::random_device{}()});
for (int i = 0; i < size; i++) {
std::cout << names[i]
<< '\n'; // Don't use std::endl unless you actually need it
}
return 0;
}
This is not ideal code, though. Any change to the size of the input file requires changing the code and re-compiling. The biggest single change was to get rid of std::random_shuffle and use std::shuffle() instead. std::random_shuffle was deprecated with C++14 and removed in C++17. It's bad to use it. std::shuffle() does add the requirement of providing a PRNG, but it's not so bad. It leads to better code if you have a PRNG that needs to randomize many different things in a bigger program. This is because it's good to have a single PRNG and let it live for the length of your program as opposed to constantly building new ones.
And the C-array just makes things a bit clunkier. Enter std::vector.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <random> // std::mt19937; needed to feed std::shuffle()
#include <string>
#include <vector>
int main() {
std::ifstream readName("names.txt");
if (!readName) { // Always check that you successfully opened the file.
std::cerr << "Error opening file.\n";
return 1;
}
std::vector<std::string> names;
std::string name;
while (std::getline(readName, name)) { // Retool the loop entirely
names.push_back(name);
}
readName.close();
std::shuffle(std::begin(names), std::end(names),
std::mt19937{std::random_device{}()});
for (const auto& i : names) {
std::cout << i << '\n';
}
return 0;
}
The vector can grow as needed, so you see how much simpler the loop that reads the names becomes. It's also more flexible since you don't have to know ahead of time how many entries to expect. It will "just work." With the call to std::shuffle() I kept the std::begin(names) syntax because many consider this a best practice, but you could have also used names.begin() if you wanted since the vector class provides its own iterators.
Lets have a look at you main question:
I tried to use this but it just shuffled the letters of the first word in the array:
random_shuffle(names->begin(), names->end());
The reason that it only shuffles the first word is because of the types and usage.
So names is an array of strings.
string names[197];
The problem stems from the C world. Were arrays decay into pointers exceedingly easily (just by being used in an expression). So here names-> has decayed into a pointer to the first element of the array. This allows you to use the -> operator which normally only works on pointers. So you are calling the functions begin() and end() on the pointer to the first element in the array. Thus only the first name is being shuffled.
The fix this problem use std::begin() method.
// here std::begin / std::end find the beginning and end
// of the array. So you are shuffling the array.
random_shuffle(std::begin(names), std::end(names));
But I would note that random_shuffle() is outdated. As mentioned by #sweenish you should use std::shuffle() See his answer for details.
A couple of things we can improve:
You use C array to store the names. Sure it works, but it is susceptible to a couple of issues because it can not be re-sized (and unless you think the file is never going to be changed that may be an issue). Potentially a hidden issue to a far distant maintainer.
std::vector<std::string> names; // resizeable container.
I would note that the current implementation ignores the first line. Then reads the first word from each subsequent line. There is also a slight issue that the last line may be empty and you read an empty name into the last element of the array (but you don't track how many names you read so unless you use all elements in the array you may never notice that).
I would change that. As it is not obvious. I would delibrately and seprately ignore the first line. Then I would simply read all the first words into a vector (so you know the size).
std::string line
std::getline(file, line); // Ignore the first line.
std::string word
while(file >> word) {
names.push_back(word);
std::getline(file, line); // ignore the rest of the line.
}
We could get fancy. Use iterators to simply create the array directly.
class Line
{
std::string firstWord;
friend std::istream& operator>>(std::istream& stream, Line& data) {
stream >> data.firstWord;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); retrun stream;
}
operator std::string() const {
return firstWord;
}
};
Now you can create and load the vector in one line:
std::vector<std::string> names(std::istream_iterator<Line>(file),
std::istream_iterator<Line>{});
Then finally copy the names out can be made easier using foreach loop. Also don't use std::endl in a loop like this. It forces a flush of the underlying bugger after each new line. This is very ineffecient.
for(auto const& name: names) {
std::cout << name << "\n";
}
So the result is:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
class Line
{
std::string firstWord;
friend std::istream& operator>>(std::istream& stream, Line& data) {
stream >> data.firstWord;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); return stream;
}
operator std::string() const {
return firstWord;
}
};
int main()
{
std::ifstream file("names.txt");
std::string line
std::getline(file, line); // Ignore the first line.
std::vector<std::string> names(std::istream_iterator<Line>(file),
std::istream_iterator<Line>{});
random_shuffle(std::begin(names), std::end(names));
for(auto const& name: names) {
std::cout << name << "\n";
}
}

Copy vector of vectors into 1D array

I have following C++ object
std::vector<std::vector<SomeClass>> someClassVectors(sizeOFOuter);
where I know the size of "outer" vector, but sizes of "inner" vectors varies. I need to copy the elements of this structure into 1D array like this:
SomeClass * someClassArray;
I have a solution where I use std::copy like this
int count = 0;
for (int i = 0; i < sizeOfOuter; i++)
{
std::copy(someClassVectors[i].begin(), someClassVectors[i].end(), &someClassArray[count]);
count += someClassVectors[i].size();
}
but the class includes large matrices which means I cannot have the "vectors" structure and 1D array allocated twice at the same time.
Any ideas?
Do you previously preallocate someClassArray to a given size? I'd suggest using 1D vector for getting rid of known problems with the plain array if possible.
what about something like this:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<std::vector<int>> someClassVectors {
{1,2,3},
{4,5,6},
{7,8,9}
};
std::vector<int> flat;
while (!someClassVectors.empty())
{
auto& last = someClassVectors.back();
std::move(std::rbegin(last), std::rend(last), std::back_inserter(flat));
someClassVectors.pop_back();
}
std::reverse(std::begin(flat), std::end(flat));
int * someClassArray = flat.data();
std::copy(someClassArray, someClassArray + flat.size(), std::ostream_iterator<int>(std::cout, " "));
}
The extra reverse operation doesn't have an effect on memory metrics - such an approach helps to avoid unneeded memory reallocations resulting from removing vector elements from beginning to end.
EDIT
Inspired by comments I changed copy to move semantics
Embrace Range-v3 (or whatever will be introduced in C++20) and write a solution in (almost) a single line:
auto flattenedRange = ranges::views::join(someClassVectors);
this gives you a range in flattenedRange, which you can loop over or copy somewhere else easily.
This is a possible use case:
#include <iostream>
#include <vector>
#include <range/v3/view/join.hpp>
int main()
{
std::vector<std::vector<int>> Ints2D = {
{1,2,3},
{4},
{5,6}
};
auto Ints1D = ranges::views::join(Ints2D);
// here, going from Ints1D to a C-style array is easy, and shown in the other answer already
for (auto const& Int : Ints1D) {
std::cout << Int << ' ';
}
std::cout << '\n';
// output is: 1 2 3 4 5 6
}
In case you want to get a true std::vector instead of a range, before writing it into a C-style array, you can include this other header
#include <range/v3/range/conversion.hpp>
and pipe join's output into a conversion function:
auto Ints1D = ranges::views::join(Ints2D) | ranges::to_vector;
// auto deduces std::vector<int>
In terms of standard and versions, it doesn't really require much. In this demo you can see that it compiles and runs just fine with
compiler GCC 7.3
library Range-v3 0.9.1
C++14 standard (option -std=c++14 to g++)
As regards the copies
ranges::views::join(Ints2D) is only creating a view on Ints2D, so no copy happens; if view doesn't make sense to you, you might want to give a look at Chapter 7 from Functional Programming in C++, which has a very clear explanation of ranges, with pictures and everything;¹
even assigning that output to a variable, auto Ints1D = ranges::views::join(Ints2D);, does not trigger a copy; Ints1D in this case is not a std::vector<int>, even though it behaves as one when we loop on it (behaves as a vector because it's a view on it);
converting it to a vector, e.g. via | ranges::to_vector, obviously triggers a copy, because you are no more requesting a view on a vector, but a true one;
passing the range to an algorithm which loops on its elements doesn't trigger a copy.
Here's an example code that you can try out:
// STL
#include <iostream>
#include <vector>
// Boost and Range-v3
#include <boost/range/algorithm/for_each.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/range/conversion.hpp>
struct A {
A() = default;
A(A const&) { std::cout << "copy ctor\n"; };
};
int main()
{
std::vector<std::vector<A>> Ints2D = {
{A{},A{}},
{A{},A{}}
};
using boost::range::for_each;
using ranges::to_vector;
using ranges::views::join;
std::cout << "no copy, because you're happy with the range\n";
auto Ints1Dview = join(Ints2D);
std::cout << "copy, because you want a true vector\n";
auto Ints1D = join(Ints2D) | to_vector;
std::cout << "copy, despite the refernce, because you need a true vector\n";
auto const& Ints1Dref = join(Ints2D) | to_vector;
std::cout << "no copy, because we movedd\n";
auto const& Ints1Dref_ = join(std::move(Ints2D)) | to_vector;
std::cout << "no copy\n";
for_each(join(Ints2D), [](auto const&){ std::cout << "hello\n"; });
}
¹ In an attempt to try giving a clue of what a range is, I would say that you can imagine it as a thing wrapping two iterators, one poiting to the end of the range, the other one pointing to the begin of the range, the latter being incrementable via operator++; this opearator will take care of the jumps in the correct way, for instance, after viewing the element 3 in Ints2D (which is in Ints2D[0][2]), operator++ will make the iterator jump to view the elment Ints[1][0].

C++ Using naked, instead of smart pointers

Consider the following code.
#include <iostream>
#include <vector>
#include <memory>
int main() {
std::vector<std::string> vec;
for(int i =0;i<10;i++){
vec.push_back("adsf");
}
std::string* myPoint = &vec[1];
*myPoint = "this works";
std::shared_ptr<std::string> str_ptr = std::make_shared<std::string>(vec[0]);
str_ptr->push_back('this does not push_back to the end of the string stored in at vec[0]');
for(int i =0;i<10;i++){
std::cout << vec[i] << std::endl; //does not print the new value set by str_ptr
}
return 0;
}
What I want here is to update a value in vec through a pointer. As I've understood smart pointers are no good for this task. Is using a naked pointer here, an acceptable alternative?
make_shared does not mean "make this already-existing thing be shared".
It means "make a new shared thing with the following constructor arguments".
You're dynamically allocating a new string that copies vec[0] (i.e. using the copy constructor).
If you want vec[0] to be a shared_ptr<string>, then you need to make it one from the start.

How to make unordered_map<string*, V> hash by value instead of reference?

I have the following
The two equivalent strings bar and bartest do not map to the same value in unordered_map. How can I make this happen?
Of course they don't map to the same value, const string* is a pointer type and since you call new string twice, you end up with two separate objects that don't have memory identity (the pointers are not equal).
What's worse, you leak both of them at the end of your program.
What's (arguably) worse still, owning raw pointers and naked new calls are considered harmful in modern c++.
Luckily it's all fixed with unordered_map<string, int> - no pointers required whatsoever.
Your C++ is in fact "Java-- + C".
Remove all those silly pointers.
All you need is unordered_map<string,int> and use plain values instead of heap-allocated "news"
just do
#include <unordered_map>
#inclide <string>
#include <iostream>
int main()
{
unordered_map<string,int> mymap;
mymap["bar"] = 5;
mymap["bartest"] = 10;
std::cout << mymap["bar"] << ' ' << mymap["bartest"] << '\n';
return 0;
}

My code prints out the address instead of the array value?

What is wrong with my code? I want to print out the array, but when I try to do so it seems to print out an address instead.
#include <iostream>
#include <ctime>
#include <stdlib.h>
using namespace std;
int main ()
{
srand(time(NULL));
int array[9]= {0};
for (int i=0;i<=8;i++)
{
array[i]= (rand()%101);
}
cout<< array;
system ("PAUSE");
return 0;
}
You can't just cout an array. Arrays are not cout-able. Whenever you successfully cout something of type T, it means that there's a dedicated overloaded << operator designed specifically to cout values of type T. And there's no dedicated << operator for cout-ing arrays (aside from strings). For this reason the compiler chooses the closest match for the given argument type: a << operator for pointers. Since arrays are convertible to pointers, that << is applicable here.
If you want to cout the values of all elements of your array, you'll have to either cout them manually, one by one, or use some standard algorithm that can do it for you. For example
std::copy(array, array + 9, std::ostream_iterator<int>(std::cout, " "));
You'll need to do a loop to output each array element on its own.
The problem is that C++ doesn't always know the size of the array, so it can't default to outputting the whole thing as you would expect.
You need to iterate over the array and print each element like how you assigned value at each index. Since array decays to a pointer to the first element in the sequence, you are getting the address.
std::cout doesn't have an overload for int array[9], so this decays to a pointer (int*) and this is what you'll see displayed (something like 0x7fffe47142d0).
To print the ints in the array individually, you will need to use a loop construct (like the for- loop you are using for populating the array) and send each of the ints to std::cout in turn, perhaps with some whitespace to format them.
Once you get the hang of C++ and its standard library, you may want to investigate how to do this with std::copy(), but I suspect this is a bit advanced for your homework.
C++ decays array type to a pointer type when the value is passed as argument to a function. C++11 has std::array (and TR1 specifies std::tr1::array) which retains the size of the array. Here is your example modified to use std::array:
#include <array>
#include <iostream>
#include <ctime>
#include <stdlib.h>
template<typename T, std::size_t N>
std::ostream& operator<< (std::ostream& ostm, const std::array<T, N>& a)
{
for (auto const& x : a)
ostm << x << ' ';
return ostm;
}
int main ()
{
srand(time(NULL));
std::array<int, 9> array;
for (auto& x : array)
x = rand() % 101;
std::cout<< array << std::endl;
}