I just started learning boost shared pointers.
I wrote a short program, results look good but I'm not sure if memory is deallocating well with my code. I would like to ask, if someone could look at my code and tell if I correctly use shared pointers.
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>
#include <string>
#define VECTSIZE 10
typedef boost::shared_ptr<std::string> StringPtr;
typedef std::vector<StringPtr> StringVect;
///////////////////////////////////////////////////////////////
std::string random_string (size_t length);
///////////////////////////////////////////////////////////////
int main()
{
StringVect vect;
for (int i = 0; i < VECTSIZE; i++)
{
std::string * stdstr;
stdstr = new std::string;
*stdstr = random_string(10);
std::cout << *stdstr << "\r\n";
StringPtr str(stdstr);
vect.push_back(str);
}
std::cout << "\r\n\r\n";
for (int i = 0; i < VECTSIZE; i++)
{
std::cout << *vect[i] << "\r\n";
}
vect.clear();
system("pause");
return 0;
}
///////////////////////////////////////////////////////////////
std::string random_string (size_t length)
{
auto randchar = []() -> char
{
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t max_index = (sizeof(charset) - 1);
return charset[ rand() % max_index ];
};
std::string str(length,0);
std::generate_n( str.begin(), length, randchar );
return str;
}
Thanks for any advice; I hope it'll be helpful for me and others.
Your use is correct in the sense that there are no direct memory leaks. However, you're not really exception safe - if random_string throws, you'll leak stdstr. It's better (and more idiomatic) to bypass rwa pointers entirely. Here's an example with using std::shared_ptr:
for (int i = 0; i < VECTSIZE; i++)
{
StringPtr str = std::make_shared<std::string>(); // Encapsulates new
*str = random_string(10);
std::cout << *str << '\n'; //No \r here: text streams insert it on Windows automatically
vect.push_back(str);
}
Also, as #ForEveR noted, there's little reason to allocate std::string dynamically in real world apps. But I assume you use it just as an excercise with smart pointers, which is fine of course.
All is okay, but you needn't vect.clear() string. However, string is value-type, don't use shared_ptr of string.
Related
im currently setting up the highscore-part for a game and I have a very weird problem because of the weird behaviour of the std::sort function.
Im doing the whole thing in RAD Studio 10.2 (Embarcadero IDE) in C++.
So he is my code:
std::string Line;
int count = 0;
int i = 0;
ifstream File("Highscore.txt");
if(File.is_open())
{
while(getline(File, Line))
{
count += 1;
}
File.close();
}
ifstream ReadFile("Highscore.txt");
if(ReadFile.is_open())
{
string *scores = NULL;
scores = new string[count];
while(getline(ReadFile, Line))
{
scores[i] = Line;
i += 1;
}
ReadFile.close();
std::sort(scores, (scores+count));
UnicodeString Uscores1 = scores[0].c_str();
UnicodeString Uscores2 = scores[1].c_str();
UnicodeString Uscores3 = scores[2].c_str();
UnicodeString Uscores4 = scores[3].c_str();
UnicodeString Uscores5 = scores[4].c_str();
LScore1->Caption = Uscores1;
LScore2->Caption = Uscores2;
LScore3->Caption = Uscores3;
LScore4->Caption = Uscores4;
LScore5->Caption = Uscores5;
}
I get no errors from the compiler/linker and everything work should fine.
The string array gets filled correctly and so on.
But its not sorting.
To show the problem to you I made a screenshot - on the left you can see the txtfile with the scores; on the right you can see the output after the sorting algorithm:
My question now is why this is happening?
Thanks for you help
Welcome to C++. Since you want to list numbers by rank, read them as int not string. Forget about operator new. You will not need it for years, if ever. Use standard containers like std::vector, which take care of the memory allocation and de-allocation transparently.
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
int main() {
using namespace std;
vector<int> scores;
{
ifstream inp("Highscore.txt");
int next;
while (inp >> next) {
scores.push_back(next);
}
}
sort(scores.begin(), scores.end());
for (auto s : scores) {
cout << s << '\n';
}
return 0;
}
How about something like:
int i = 0;
int * scoresInteger = NULL;
scoresInteger = new int[count];
for(i = 0; i < count; i++)
{
scoresInteger[i] = std::stoi(scores[i]);
}
std::sort(scoresInteger, scoresInteger + count);
If you need to, you can convert the integers back into strings using targetStrings[i] = std::to_string(scoresInteger[i]).
string * targetScores = NULL;
targetScores = new std::string[count];
for(i = 0; i < count; i++)
{
targetScores[i] = std::to_string(scoresInteger[i]);
}
delete [] scoresInteger;
scoresInteger = NULL;
Don't forget to delete [] targetScores later.
My question now is why this is happening?
Because your scores are compared as strings and not as ints. Because of that "3" is greater that "25"
std::cout << std::boolalpha << (std::string("3") > std::string("25")) << std::endl; // true
Luckily you can pass a custom comparator (or lambda) to the std::sort to make it behave just as you want:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
const int count = 5;
std::string scores[count] = { "35","25","3","4","5" };
// TWEAKED SORT
std::sort(scores, scores + count, [](std::string const &s1, std::string const &s2)
{
return std::stoi(s2) < std::stoi(s1);
});
// TEST
for (auto const &s : scores)
{
std::cout << s << std::endl;
}
}
The compared strings in the above example are converted to ints and then compared, resulting in the desired sorting order.
35
25
5
4
3
Please note that I do not agree with the rest of your code and I think you should rethink the implementation, as it would be much easier, safer and more efficient to use std::vector<std::string> for your task.
There is already a question for this here: How to repeat a string a variable number of times in C++? However because the question was poorly formulated primarily answers about character multiplication were given. There are two correct, but expensive answers, so I'll be sharpening the requirement here.
Perl provides the x operator: http://perldoc.perl.org/perlop.html#Multiplicative-Operators which would let me do this:
$foo = "0, " x $bar;
I understand that I can do this with the helper functions such as those in the other answer. I want to know can I do this without my own helper function? My preference would be something that I could initialize a const string with, but if I can't do that I'm pretty sure that this could be answered with a standard algorithm and a lambda.
You can either override the multiplication operator
#include <string>
#include <sstream>
#include <iostream>
std::string operator*(const std::string& str, size_t times)
{
std::stringstream stream;
for (size_t i = 0; i < times; i++) stream << str;
return stream.str();
}
int main() {
std::string s = "Hello World!";
size_t times = 5;
std::string repeated = s * times;
std::cout << repeated << std::endl;
return 0;
}
... or use a lambda ...
#include <string>
#include <sstream>
#include <iostream>
int main() {
std::string s = "Hello World!";
size_t times = 5;
std::string repeated = [](const std::string& str, size_t times) {std::stringstream stream; for (size_t i = 0; i < times; i++) stream << str; return stream.str(); } (s, times);
std::cout << repeated << std::endl;
return 0;
}
... or use a lambda with reference capturing ...
#include <string>
#include <sstream>
#include <iostream>
int main() {
std::string s = "Hello World!";
size_t times = 5;
std::string repeated = [&s, ×]() {std::stringstream stream; for (size_t i = 0; i < times; i++) stream << str; return stream.str(); }();
std::cout << repeated << std::endl;
return 0;
}
Instead of using std::stringstream you could also use std::string in combination with std::string::reserve(size_t) as you already know (or can calculate) the size of the result string.
std::string repeated; repeated.reserve(str.size() * times);
for (size_t i = 0; i < times; i++) repeated.append(str);
return repeated;
This might be faster: Compare http://goo.gl/92hH9M with http://goo.gl/zkgK4T
It is possible to do this using just a standard algorithm and a lambda with generate_n, but it still cannot initialize a const string it needs to be done in a separate line:
string foo;
const auto bar = 13U;
generate_n(back_inserter(foo), bar * 3U, [](){
static const char multiplicand[] = "0, ";
static const auto length = strlen(multiplicand);
static auto i = 0U;
return multiplicand[i++ % length];});
I've created a live example here: http://ideone.com/uIt2Ee But as is probably been made plain by all the question comments, the requirement of doing this in a single line results in inferior code. Right off the bat, we can see that the bare constant, 3, represents the size of multiplicand and unnecessarily requires changes to the initialization of multiplicand to also update this literal.
The obvious improvement that should be made is:
string foo;
const auto bar = 13U;
const char multiplicand[] = "0, ";
const auto length = strlen(multiplicand);
generate_n(back_inserter(foo), bar * length, [&](){
static auto i = 0U;
return multiplicand[i++ % length];
});
The next improvement would be eliminating the reallocation as foo grows, which could be expensive if bar or length is large. That can be accomplished by constructing foo with sufficient space to contain the entire generated string:
const auto bar = 13U;
const char multiplicand[] = "0, ";
const auto length = strlen(multiplicand);
string foo(bar * length, '\0');
generate_n(foo.begin(), bar * length, [&](){
static auto i = 0U;
return multiplicand[i++ % length];
});
[Live Example]
I have a vector<std::string> variable. I need to pass it onto a method which accepts char**as an input parameter.
how to do this ? If possible I need to pass a writable one.
Update 1:
In a tool for creating a service method, i give parameters as std::vector, but it sets automatically the qualifier as &, which means my method definition generated by the tool will look as:
std::string SvcImpl::myMethodname ( const std::string par1, const std::vector< std::string >& par2, const std::vector< std::string >& par3 )
{
}
This method gets called automatically with values in the patameter passed.
Now from inside this method I'm going to call a method in a dll in a lib folder which looks like:
int method_to_be_called(char* par1, char ** par2, char ** par3, void* pRetValue);
for par1 --> I'm passing (char*)par1.c_str()
I need to know how to pass variables for par2 and par3 and for pRetValue.
values for par2 and par3 are available in vector but the last parameter pRetValue is an output parameter that i need to return it as std::string.
sorry if i am very confusing or asking very basic questions.
It is possible to solve the problem without copying out all the std::strings as long as the function does not modify the passed in char**. Otherwise I can see no alternative but to copy out everything into a new char**` structure (see second example).
void old_func(char** carray, size_t size)
{
for(size_t i = 0; i < size; ++i)
std::cout << carray[i] << '\n';
}
int main()
{
std::vector<std::string> strings {"one", "two", "three"};
std::vector<char*> cstrings;
cstrings.reserve(strings.size());
for(size_t i = 0; i < strings.size(); ++i)
cstrings.push_back(const_cast<char*>(strings[i].c_str()));
// Do not change any of the strings here as that will
// invalidate the new data structure that relies on
// the returned values from `c_str()`
//
// This is not an issue after C++11 as long as you don't
// increase the length of a string (as that may cause reallocation)
if(!cstrings.empty())
old_func(&cstrings[0], cstrings.size());
}
EXAMPLE 2: If the function must modify the passed in data:
void old_func(char** carray, size_t size)
{
for(size_t i = 0; i < size; ++i)
std::cout << carray[i] << '\n';
}
int main()
{
{
// pre C++11
std::vector<std::string> strings {"one", "two", "three"};
// guarantee contiguous, null terminated strings
std::vector<std::vector<char>> vstrings;
// pointers to rhose strings
std::vector<char*> cstrings;
vstrings.reserve(strings.size());
cstrings.reserve(strings.size());
for(size_t i = 0; i < strings.size(); ++i)
{
vstrings.emplace_back(strings[i].begin(), strings[i].end());
vstrings.back().push_back('\0');
cstrings.push_back(vstrings.back().data());
}
old_func(cstrings.data(), cstrings.size());
}
{
// post C++11
std::vector<std::string> strings {"one", "two", "three"};
std::vector<char*> cstrings;
cstrings.reserve(strings.size());
for(auto& s: strings)
cstrings.push_back(&s[0]);
old_func(cstrings.data(), cstrings.size());
}
}
NOTE: Revised to provide better code.
Galik's answer has a number of safety issues. Here is how I would do it in Modern C++:
#include <iostream>
#include <string>
#include <vector>
void old_func(char** carray, std::size_t size)
{
for(std::size_t i(0); i < size; ++i)
std::cout << carray[i] << '\n';
}
void other_old_func(const char** carray, std::size_t size)
{
for(std::size_t i(0); i < size; ++i)
std::cout << carray[i] << '\n';
}
int main()
{
{
std::cout << "modifiable version\n";
std::vector<std::string> strings{"one", "two", "three"};
std::vector<char*> cstrings{};
for(auto& string : strings)
cstrings.push_back(&string.front());
old_func(cstrings.data(), cstrings.size());
std::cout << "\n\n";
}
{
std::cout << "non-modifiable version\n";
std::vector<std::string> strings{"four", "five", "six"};
std::vector<const char*> cstrings{};
for(const auto& string : strings)
cstrings.push_back(string.c_str());
other_old_func(cstrings.data(), cstrings.size());
std::cout << std::endl;
}
}
No messy memory management or nasty const_casts.
Live on Coliru.
Outputs:
modifiable version
one
two
three
non-modifiable version
four
five
six
The top rated answers for this question expect you to pass in a size with your char** parameters. But in method_to_be_called() there is no way to pass in a size for par2 and par3 so these lists of c-style strings probably expect to be null terminated. In other words the last string (char*) in the list of strings (char **) needs to be a null pointer. This is a common paradigm in many c libraries.
int method_to_be_called(char* par1, char ** par2, char ** par3, void* pRetValue);
The most expedient way around this is probably to go with a more c-style answer.
//directly create char** par2
std::vector<std::string> par2Vect{"one", "two", "three"};
char ** par2 = (char**) malloc( sizeof(char*)*(par2Vect.size() + 1) );
for(size_t i = 0; i < par2Vect.size(); ++i)
{
par2[i] = strdup(par2Vect[i].c_str());
}
// set the last entry to null to signify the end of the list
par2[par2Vect.size()] = nullptr;
// call your library
method_to_be_called(..., par2,...);
// delete par2
for(size_t i = 0; i < par2Vect.size(); ++i)
{
// free memory for each c-style string
free(par2[i]);
}
// free memory for outer char* array
free(par2);
I believe this is rather easy and can be done without too much of complexity.
std::vector<std::string> vector = {"a", "std::vector", "of", "std::string"};
// Result char**.
char** result = new char*[vector.size()];
for (int index = 0; index < vector.size(); index++) {
result[index] = const_cast<char*>(vector[index].c_str());
}
// Use the result.
delete[] result;
// Deallocate the memory from heap after usage.
So I am working on a tool that dereferences the values of some addresses, it is in both C and C++, and although I am not familiar with C++ I figured out I can maybe take advantage of the string type offered by C++.
What I have is this:
unsigned char contents_address = 0;
unsigned char * address = (unsigned char *) add.addr;
int i;
for(i = 0; i < bytesize; i++){ //bytesize can be anything from 1 to whatever
if(add.num == 3){
contents_address = *(address + i);
//printf("%02x ", contents_address);
}
}
As you can see what I am trying to do is dereference the unsigned char pointer. What I want to do is have a string variable and concatenate all of the dereferenced values into it and by the end instead of having to go through a for case for getting each one of the elements (by having an array of characters or by just going through the pointers) to have a string variable with everything inside.
NOTE: I need to do this because the string variable is going to a MySQL database and it would be a pain to insert an array into a table...
Try this that I borrowed from this link:
http://www.corsix.org/content/algorithmic-stdstring-creation
#include <sstream>
#include <iomanip>
std::string hexifyChar(int c)
{
std::stringstream ss;
ss << std::hex << std::setw(2) << std::setfill('0') << c;
return ss.str();
}
std::string hexify(const char* base, size_t len)
{
std::stringstream ss;
for(size_t i = 0; i < len; ++i)
ss << hexifyChar(base[i]);
return ss.str();
}
I didn't quite understand what you want to do here (why do you assign a dereferenced value to a variable called ..._address)?.
But maybe what you're looking for is a stringstream.
Here's a relatively efficient version that performs only one allocation and no additional function calls:
#include <string>
std::string hexify(unsigned char buf, unsigned int len)
{
std::string result;
result.reserve(2 * len);
static char const alphabet[] = "0123456789ABCDEF";
for (unsigned int i = 0; i != len)
{
result.push_back(alphabet[buf[i] / 16]);
result.push_back(alphabet[buf[i] % 16]);
{
return result;
}
This should be rather more efficient than using iostreams. You can also modify this trivially to write into a given output buffer, if you prefer a C version which leaves allocation to the consumer.
I'm trying to write a code which stores strings in an array. I'm trying to do it with char* but I couldn't achieve. I search the net but couldn't find an answer. I've tried the code below, but it didn't compile.I use string stream because at some point I need to concatenate a string with an integer.
stringstream asd;
asd<<"my name is"<<5;
string s = asd.str();
char *s1 = s;
> I'm trying to write a code which stores strings in an array.
Well, first you'll need an arary of strings. I don't like using naked arrays, so I use std::vector:
std::vector<std::string> myStrings;
But, I understand you have to use an array, so we'll use an array instead:
// I hope 20 is enough, but not too many.
std::string myStrings[20];
int j = 0;
> I use string stream because ...
Okay, we'll use stringstream:
std::stringstream s;
s << "Hello, Agent " << 99;
//myStrings.push_back(s.str()); // How *I* would have done it.
myStrings[j++] = s.str(); // How *you* have to do it.
That gets us one string, but you want an array of them:
for(int i = 3; i < 11; i+=2) {
s.str(""); // clear out old value
s << i << " is a" << (i==9?" very ":"n ") << "odd prime.";
//myStrings.push_back(s.str());
myStrings[j++] = s.str();
}
Now you have an array of strings.
Complete, tested program:
#include <sstream>
#include <iostream>
int main () {
// I hope 20 is enough, but not too many.
std::string myStrings[20];
int j = 0;
std::stringstream s;
s << "Hello, Agent " << 99;
//myStrings.push_back(s.str()); // How *I* would have done it.
myStrings[j++] = s.str(); // How *you* have to do it.
for(int i = 3; i < 11; i+=2) {
s.str(""); // clear out old value
s << i << " is a" << (i==9?" very ":"n ") << "odd prime.";
//myStrings.push_back(s.str());
myStrings[j++] = s.str();
}
// Now we have an array of strings, what to do with them?
// Let's print them.
for(j = 0; j < 5; j++) {
std::cout << myStrings[j] << "\n";
}
}
How about something like this?
vector<string> string_array;
stringstream asd;
asd<<"my name is"<<5;
string_array.push_back(asd.str());
char *s1 = s;
Is illegal. You either need:
const char *s1 = s.c_str();
if you're not set on char*, or you'll need to allocate a new char* and use strcpy to copy the contents from the string.
Just change your code to
char const* s1 = s.c_str();
because a pointer to char can't store a string object, only a pointer to char, which is what c_str() returns.
I wouldn't use the char * directly. I would wrap it in something like the template below. You can override the operators you need to do any more operations (example, I would make data a private member, and override the operators to make the data print out cleanly). I did the assignment operator just to demonstrate how clean that could make code.
#include "MainWindow.h"
#include <stdio.h>
using namespace std;
template<size_t size>
class SaferChar
{
public:
SaferChar & operator=(string const & other)
{
strncpy(data, other.c_str(), size);
return *this;
}
char data[size];
};
int main(int argc, char *argv[])
{
SaferChar<10> safeChar;
std::string String("Testing");
safeChar = String.c_str();
printf("%s\n", safeChar.data);
return 0;
}