I am working on a challenge given to me by a friend and to complete it I need to pass a mutable string into a function without prior declaration. (The function preforms some operations on the string so it must be mutable and due to constraints in the challenge I cannot declare the variable before the function call. Basically can
myFunction("abcdef");
be altered in such a way that the string is declared in the function call and passed or so that the passed string is not declared in non-mutable memory.
Here is a version which changes the call to be
myFunction("abcdef"_ncs);
I guess, this innocent addition for "non-const string" should be permissible. Here is the code:
#include <cstring>
#include <cstddef>
#include <iostream>
void myFunction(char* x) {
std::cout << "x=" << x << "\n";
}
struct tmp_string {
char* buffer;
tmp_string(char const* str, std::size_t n)
: buffer(std::strcpy(new char[n + 1], str)) {
}
tmp_string(tmp_string&& other): buffer(other.buffer) { other.buffer = 0; }
~tmp_string() { delete[] buffer; }
operator char*() { return buffer; }
};
tmp_string operator"" _ncs(char const* str, std::size_t n) {
return tmp_string(str, n);
}
int main()
{
myFunction("abcdef"_ncs);
}
I didn't use std::string primarily because there is no neat conversion from a std::string to a non-const string. The only approach I could think of would be
myFunction(&std::string("abcdef")[0]);
At least, it would also neatly clean up after itself (as does the approach using tmp_string above). Note that starting with C++11 the approach taking the address of the first byte also yields a null-terminated string (for C++03 the string wasn't guaranteed to be null-terminated; since I had trouble verifying this guarantee: it is in 21.4.5 [string.access] paragraph 2).
Here is a simple way to do this.
#include <iostream>
using namespace std;
void MyFunc(char* c)
{
c[0] = 's';
cout << c << endl;
delete[] c;
}
int main()
{
MyFunc(new char[3]{'a','b', 0});
return 0;
}
Related
I am trying to understand how move semantics work in particular with the standard string. My primary concern is how to expose a string member variable of a class through a method, for example a getter.
So I made this example program.
#include <iostream>
#include <string>
using namespace std;
class Object {
string _s;
public:
Object(string s) : _s(s) {}
string get1() { return _s; }
string get2() { return move(_s); }
void print() { cout << "'" << _s << "'" << endl; }
};
int main() {
Object obj("0123456789ABCDEF_");
string s1 = obj.get1();
obj.print(); // prints '0123456789ABCDEF_'
string s2 = obj.get2();
obj.print(); // prints ''
}
Both methods get1() and get2() return by value.
I expected the get1() to automatically move the internal _s, however as you can see that is not the case. The get2() on the other hand makes the move, though this is expected as I explicitly ask for it.
So the question is why get1() does not move _s.
Phil1970 answered this in a comment above.
Move semantics work with rvalues. The _s member variable is apparently an lvalue and that is why get1() results in a copy instead of a move.
I am trying to create a constructor to load a resource from any istream given to it. I cannot seem to figure out the best way to pass the istream parameter into a constructor.
Loader::Loader(istream stream);
This one is obviosly bad due to object slicing, so no option.
Loader::Loader(istream& stream);
This is what I am using now and seems fairly alright. It has one significant issue though - you can't give it a temporary since temporaries cannot bind to non-const references! For example, the following won't work:
Container():
mLoader(ifstream("path/file.txt", ios::binary)
{
}
This is rather a limitation since I am now forced to store the ifstream as a member variable of Container just to extend its lifetime.
Since the problem is with non-const references, one could have though of this:
Loader::Loader(const istream& stream);
But since .seek() etc are non-const, this is not an option either...
So, how can this problem be solved in a neat way?
if your compiler is c++11 or better you can simply provide a version of the constructor that takes the istream as an r-value reference:
void Loader::Loader(std::istream&& is)
quick example:
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
struct Loader
{
Loader(std::istream& is)
{
read(is);
}
Loader(std::istream&& is)
{
read(is);
}
void read(std::istream& is)
{
is >> std::quoted(x);
is >> std::quoted(y);
}
std::string x, y;
};
std::ostream& operator<<(std::ostream& os, const Loader& l)
{
os << "x = " << l.x;
os << ", y = " << l.y;
return os;
}
auto main() -> int
{
using namespace std;
Loader l(istringstream(R"text("donkey" "horse")text"));
cout << l << endl;
istringstream not_temp(R"text("apple" "banana")text");
Loader l2(not_temp);
cout << l2 << endl;
return 0;
}
expected output:
x = donkey, y = horse
x = apple, y = banana
The example
Container():
mLoader(ifstream("path/file.txt", ios::binary)
{
}
… is ill-conceived, because the lifetime of the temporary would be just the constructor call. Then you'd be left with a dangling reference. Using that reference would be Undefined Behavior.
However, technically, in order to be able to pass a temporary to a reference-to-non-const formal argument, just define a little helper like this:
template< class Type >
auto temp_ref( Type&& o )
-> Type&
{ return o; }
Then you can call e.g. foo( temp_ref( Whatever() ) ), but just keep in mind that the lifetime of that temporary is the full-expression that it occurs in.
Passing a pointer to a newly created object would work.
Loader(istream * pstream)
{
try
{
// ......
delete pstream;
throw;
}
catch(...)
{
delete pstream;
}
}
Container():
mLoader(new ifstream("path/file.txt", ios::binary))
{
}
Let's consider the following code (live at: http://ideone.com/3Ky4Kr)
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
class StrStrTest {
public:
StrStrTest(const std::string& ba) {
a = (char*)calloc(1, ba.length() + 1);
strcpy(a, ba.c_str());
}
virtual ~StrStrTest() {
free(a);
}
private:
char* a;
friend std::basic_ostream<char>& operator << (std::basic_ostream<char>& ss, const StrStrTest& a);
friend std::basic_istream<char>& operator >> (std::basic_istream<char>& ss,const StrStrTest& a);
};
std::basic_ostream<char>& operator << (std::basic_ostream<char>& ss, const StrStrTest& a) {
ss << a.a;
return ss;
}
std::basic_istream<char>& operator >> (std::basic_istream<char>& ss,
const StrStrTest& a) {
ss >> a.a; // <<-- HERE
// a.a = NULL;
return ss;
}
int main()
{
StrStrTest bb("foo");
std::cin >> bb;
std::cout << bb;
}
Firstly, why does it compile? On the line marked with <<-- HERE I (subtly) modify a const object. (obviously a.a = NULL; does not compile, that's too obvious).
Secondly does this lead to undefined behaviour?
PS: Please don't consider that the code is not safe, might overwrite memory it does not own, char* vs. std::string, etc... I know these, and it is not the point of the question, this is not production code.
The overload you are using is this: operator>>(std::istream&, char*). It takes a char*, by value. It doesn't modify the pointer (i.e. It doesn't change the pointer to point somewhere else). It modifies the data which the pointer holds the address of, writing a null terminated c-string to that location. So, the const-ness of your object is not being violated, because that data is not part of your object.
If you try to do something like this:
a.a = NULL;
That is modifying a member of your object, and so is not allowed.
Secondly does this lead to undefined behaviour?
It can, if a.a does not point to properly allocated memory with enough space for the next space delimited char data in the stream. But not as a result of anything to do with the const-ness of the StrStrTest object.
I have a problem in my string class. After cin.get compiler display me this expression. Where did I go wrong?
//Source.cpp
#include <iostream>
#include <string>
#include "str.h"
using namespace std;
int main()
{
str S1 = "Hello, world!";
str S2 = "LOL";
str S3 = S2;
cout << S3.cstr() << endl;
cout << S1.size() << ": " << S1.cstr() << endl;
cin.get();
}
//str.h
#ifndef STR_H
#define STR_H
class str
{
public:
str(const char* = "");
~str();
void operator=(const char*);
void operator=(str);
const char* cstr();
int size();
private:
void newString(const char*);
char* charPtr;
int Size;
};
#endif
//str.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <cstring>
using std::strlen;
using std::strcpy;
#include "str.h"
str::str(const char* cstr)
{
newString(cstr);
}
str::~str()
{
delete[] charPtr;
}
const char* str::cstr()
{
return charPtr;
}
void str::newString(const char* cstr)
{
delete[] charPtr;
Size = strlen(cstr);
charPtr = new char[Size + 1];
strcpy(charPtr, cstr);
}
void str::operator=(const char* cstr)
{
newString(cstr);
}
int str::size()
{
return Size;
}
You didn't obey the rule of three. You have user defined destructor and copy assignment operator, but you haven't defined a copy constructor. The compiler helpfully</sarcasm> defined one for you.
On this line:
str S3 = S2;
You copy initialize S3. As you can see from the rules in the linked page:
If T is a class type and the type of other is cv-unqualified version of T or a class derived from T, the constructors of T are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.
The best matching constructor happens to be the str(const str&); which was added by the compier. The default copy constructor does not make a copy of the data pointed by the charPtr but just copies the pointer instead.
When S2 goes out of scope, after cin.get();, it's destructor deletes S2.charPtr. Next, S3 is destroyed and it's destructor tries to delete S3.charPtr which has the same value as S2.charPtr and is therefore already deleted. This has undefined behaviour. Quick googling suggests that _BLOCK_TYPE_IS_VALID assertion fails if heap pointer is invalid. I'm guessing it's likely result of this undefined behaviour.
Solution: Implement the copy constructor str(const str&); so that copies don't share data.
I was wondering if it is possible to change the return type of a function based on the type of variable it is being assigned to. Here's a quick example of what I mean.
I want to create a function that parses a variable of int, bool, or float from a string. For example...
Int value = parse("37");
Float value = parse("3.14");
Bool value = parse("true");
I understand if I make this function a template, that the variable type must be determined from the argument list which is always going to be a string. Is there any other way of doing this with c++?
This can be done with a conversion function
struct proxy {
string str;
proxy(string const &str):str(str) { }
template<typename T> operator T() {
return boost::lexical_cast<T>(str);
}
};
proxy parse(string const &str) { return proxy(str); }
Now you just need to do
float a = parse("3.1");
And it should work well. Incidentally, you may just use the class directly. I recommend renaming it to conversion_proxy to point to the fact that it's just a proxy to a happening conversion but that it itself doesn't do conversion
struct conversion_proxy {
string str;
conversion_proxy(string const &str):str(str) { }
template<typename T> operator T() {
return boost::lexical_cast<T>(str);
}
};
float a = conversion_proxy("3.1");
I can't tell from your question if you know this or not, but you can indeed do this with a template. The only catch is that you will have to specify the type that you are converting from in each invocation instead of relying on inference (since as you said the argument type will always be the same).
template<typename T> T parse(const string& str) { /* do stuff for other types */ }
template<> int parse<int>(const string& str) { /* do stuff for ints */ }
template<> double parse<double>(const string& str) { /* do stuff for doubles */ }
template<> bool parse<bool>(const string& str) { /* do stuff for bools */ }
// etc.
And then invoke as
int value = parse<int>("37");
double value = parse<double>("3.14");
bool value = parse<bool>("true");
If you already knew this just ignore this answer, but it's not clear from your question that you are aware that this is possible.
Of course, if what you're doing isn't really generic (and so you have to specialize for each type you want to parse) then writing a template isn't the right thing to do anyway.
By the way, you can do it pretty generically with a single function like this (assuming parse is what you really want to do):
#include <sstream>
template<typename T> T parse(const string& str)
{
T t;
std::istringstream sstr(str);
sstr >> t;
return t;
}
This will work for any default-constructable, stream-extractable type, which includes all built-ins.
You could pass your output argument as a pointer or reference.
Like this:
template<class T> void parse(const std::string &input, T& output);
Then code like this:
double d; parse(input, d);
int i; parse(input, i);
should work.
However, your code looks like a perfect fit for an std::istringstream that would just be:
istringstream is(input);
input >> d;
If you have somewhat complicated formatting involved, a trick I have had pretty good luck with involves creating custom objects with custom operator>> that pulls out data.
Then it could be like:
istringstring is(input);
input >> LineExtracter(x, y, d);
I would agree with litb who was a little quicker than myself. Use the casting operators.
#include <iostream>
#include <string>
#include <sstream>
class Convertible
{
public:
int m_Integer;
bool m_Bool;
double m_Double;
Convertible() : m_Integer(0), m_Bool(false), m_Double(0.0) {};
operator int() const
{
return m_Integer;
}
operator bool() const
{
return m_Bool;
}
operator double() const
{
return m_Double;
}
};
Convertible parse(std::string data)
{
Convertible l_result;
std::istringstream converter(data);
converter >> l_result.m_Integer;
std::istringstream converter2(data);
converter2 >> l_result.m_Bool;
std::istringstream converter3(data);
converter3 >> l_result.m_Double;
return l_result;
}
void main()
{
int l_convertedInt = parse("2");
bool l_convertedBool = parse("true");
double l_convertedDouble = parse("3.14");
std::cout << "Converted '2' to " << l_convertedInt << std::endl;
std::cout << "Converted 'true' to " << l_convertedBool << std::endl;
std::cout << "Converted '3.14' to " << l_convertedDouble << std::endl;
}
Unfortunately, that isn't possible. In C++ it is not possible to overload a function based on it's return value. You either have to have 3 functions, ParseInt, ParseFloat, and ParseBool, or use a function template.
You could return void* and then cast the result as needed.
I advise against this though. C++ is a strongly typed language. The advantage of this is that the compiler can catch errors earlier than a dynamically typed language.
No this type of behavior is not possible in C++. To be allowable it would necessitate being able to define functions of the same name at the same scope that differed only by return type. This is not legal in C++.
C++ can do some return type specialization such as covariant return types on overridden virtual functions. But it does not support what you are looking for.
Here's my adaptation of #Tyler McHenry's answer for my situation where the argument to parse() is a type other than a string.
Note that I found I had to introduce a template specialization in order to avoid a type conversion warning (float to int).
(Also see live demo.)
#include <iostream>
struct MyUnion
{
public:
union {
bool bool_value;
int int_value;
float float_value;
};
};
template<typename T> T parse(const MyUnion& h)
{
T t;
if (typeid(T) == typeid(bool)) {
t = h.bool_value;
} else if (typeid(T) == typeid(int)) {
t = h.int_value;
} else if (typeid(T) == typeid(float)) {
// t = h.float_value; // see **Warning** below; use float specialization instead
}
return t;
}
// 'float' template specialization to avoid conversion warning.
template<> float parse(const MyUnion& h)
{
return h.float_value;
}
int main()
{
MyUnion mu1; mu1.bool_value = true;
MyUnion mu2; mu2.int_value = 42;
MyUnion mu3; mu3.float_value = 3.14159;
std::cout << "As bool: " << parse<bool>(mu1) << std::endl;
std::cout << "As int: " << parse<int>(mu2) << std::endl;
std::cout << "As float: " << parse<float>(mu3) << std::endl;
}
// **Warning**
// In function 'T parse(const Heterogeneous&) [with T = int]':
// Line 22: warning: converting to 'int' from 'const float'