I don't understand quite well how to make class/structure which will be like this:
std::stringstream ss;
ss.str().c_str();
I would like to do something similar like this, example:
int result = MyAssignFunction(10, 5).AddParametrs();
// or
int result = MyAssignFunction(10, 5).FirstParametr;
I cannot name this thats why I cannot find any hints.
The main question is that is even possible or not? Please give me any hint.
The function MyAssignFunction needs to return an object that have an AddParametrs member function or a FirstParametr member variable.
But you need to be aware of that the object returned by MyAssignFunction in your examples is temporary. As soon as the expression is over, then it will be destructed.
A very simple example:
#include <iostream>
struct S
{
int value;
S(int initial) : value(initial) {}
S& add1() { value++; return *this; }
S& add2() { value += 2; return *this; }
S& addN(int n) { value += n; return *this; }
int get() const { return value; }
};
int main()
{
std::cout << "Operation = " << S(0).add1().add2().add1().addN(5).get() << '\n';
}
The above little dummy program will print
Operation = 9
The expression that does the "magic" is S(0).add1().add2().add1().addN(5).get(). It first creates a (temporary) object of the structure S and passes 0 to the constructor. Then on this object we call the member function add1, which returns a reference to itself, and on that reference we call add2, and so on. Finally we call the member function get to get the final value and output it.
As you can see, we can chain any number of function calls and in any order.
The above is just a very simple example, that allows the object to chain calls on itself. A member function can return another object (or reference to), and you can then chain calls to member function of that object. That is what you are seeing in your stringstream example: The str function returns a std::string object, and you call c_str on that std::string object.
If you are looking for method chaining meaning that you can reuse the output of a function call as if it were the object your function was called upon, all you need to do is return *this. Therefore your return value should be of the class type you are trying to implement method chaining on. To avoid an unnecessary invocation of the copy constructor, you should also return by reference. Here is a little example:
#include <iostream>
class A{
A& foo(){
return *this;
}
int bar(){
return 3;
}
};
int main(){
A a;
std::cout << a.foo().foo().foo().foo().bar(); //prints 3
}
Related
I am trying to write a function, which can either return a reference to an existing object passed as a first argument (if it is in correct state) or create and return a new object using literal passed as a second argument (default).
It would be even better if a function could take not only literal, but also another existing object as a second (default) argument and return a reference to it.
Below is a trivial implementation, but it does a lot of unneeded work:
If called with lvalue as a second (default) argument, it calls a copy constructor of an argument, that is selected for return. Ideally a reference to an object should be returned.
If called with literal as a second (default) argument, it calls constructor, copy constructor and destructor, even if second (default) argument is not selected for return. It would be better if an object is constructed and returned as rvalue reference without calling copy constructor or destructor.
std::string get_or_default(const std::string& st, const std::string& default_st) {
if (st.empty()) return default_st
else return st;
}
Is there a way to accomplish this more efficiently, while still keeping simple for caller? If I am correct, this requires a function to change return type based on run-time decision made inside a function, but I cannot think of a simple solution for caller.
I'm not 100% sure I understood the combinations of requirements but:
#include <iostream>
#include <string>
#include <type_traits>
// if called with an rvalue (xvalue) as 2:nd arg, move or copy
std::string get_or_default(const std::string& st, std::string&& default_st) {
std::cout << "got temporary\n";
if(st.empty())
return std::move(default_st); // rval, move ctor
// return std::forward<std::string>(default_st); // alternative
else
return st; // lval, copy ctor
}
// lvalue as 2:nd argument, return the reference as-is
const std::string& get_or_default(const std::string& st,
const std::string& default_st) {
std::cout << "got ref\n";
if(st.empty()) return default_st;
else return st;
}
int main() {
std::string lval = "lval";
// get ref or copy ...
decltype(auto) s1 = get_or_default("", "temporary1");
decltype(auto) s2 = get_or_default("", std::string("temporary2"));
decltype(auto) s3 = get_or_default("", lval);
std::cout << std::boolalpha;
std::cout << std::is_reference_v<decltype(s1)> << "\n";
std::cout << std::is_reference_v<decltype(s2)> << "\n";
std::cout << std::is_reference_v<decltype(s3)> << "\n";
}
Output:
got temporary
got temporary
got ref
false
false
true
Edit: Made a slightly more generic version after OP:s testing. It can use a lambda, like
auto empty_check = [](const std::string& s) { return s.empty(); };
to test if the first argument is empty.
template<typename T, typename F>
T get_or_default(const T& st, T&& default_st, F empty) {
if(empty(st)) return std::move(default_st);
// return std::forward<T>(default_st); // alternative
else return st;
}
template<typename T, typename F>
const T& get_or_default(const T& st, const T& default_st, F empty) {
if(empty(st)) return default_st;
else return st;
}
Well, there a few things here.
To express what you ask for directly you can use something like std::variant<std::string, std::string&> as your function return type. Although I have not checked if variant can store a reference.
Or some equivalent from a third party library. either<> ?
You can also write your own class wrapping string and string ref.
(Not an real code)
struct StringOrRef {
enum class Type {Value, Ref} type;
union {
std::string value;
std::reference_wrapper<const std::string> ref;
};
...
};
Check the topic: discriminating union in C++.
But I think there is a bigger problem with your example!
Please consider the ownership of data. std::string takes ownership of data passed. That is why it copy data. Thus when your function returns - the called is sure it had a data and don't need to worry about it as long as (s)he holds the value.
In case you design a function to return a reference to passed argument value - you need to make sure that the value is used within the same lifespan as the argument passed (to which the ref is returned)
So consider:
StringOrRef func(strging const& a, string const& b);
...
StringOrRef val;
{ // begin scope:
SomeStruct s = get_defaul();
val = func("some value", s.get_ref_to_internal_string());
}// end of val scope
val; // is in scope but may be referencing freed data.
The problem here is the temporary object SomeStruct s. if it's member function get_ref_to_internal_string() -> string& returns a ref to a string field of that object (which is often the way it is implemented) - then when s goes out of scope - tha ref becomes invalid. that is - it is referencing freed memory which may have been given to some other objects.
And if you capture that reference in val - val will be referencing invalid data.
You will be lucky if it all end in access violation or a signal. At worst your program continues but will be crashing randomly.
For example i have code such as below
//g++ 5.4.0
#include <iostream>
struct data
{
int n;
data()
{
std::cout << "data()\n";
}
data(const data&)
{
std::cout << "data(const data&)\n";
}
data(data&&)
{
std::cout << "data(data&&)\n";
}
};
class container
{
data d;
public:
data getData()
{
return std::move(d);
}
};
int main()
{
container c;
data result = c.getData();
}
And output is:
data()
data(data&&)
I don't understand how it works. I have not declared return type as data&&, but move constructor works fine for result. Yes, code is std::move(d) but return type is not data&&. So, how does it work?
This answer changes in c++17.
data getData()
{
return std::move(d);
}
This method moves d into its return value.
data x = foo.getData();
this one constructs x from the return value of getData. However the C++ standard encourages and permits this construction to be elided if getData returns a prvalue (a value type that matches). Elision means that the identity and lifetime of the return value and x are merged. Only one object exists, not two.
This permits skipping side effects, like print statements in move constructors.
So d is the object moved from, and that move directly constructs x.
If you change getData to return data&&, now no move is done withingetData but one is done outside when you construct x.
In c++17 the return value of getData is never an object, it is a prvalue, and prvalues in c++17 are more like instructions to create objects. In effect elision is no longer optional.
If the return type is set to data (as in your case), then the returned object is a prvalue.
If the return type is set to data&&, then the returned object is an xrvalue.
In either case, the returned object is an rvalue, and result's move constructor will be called.
See also: http://stackoverflow.com/a/10159163/4509057
In C++, operator-> has special semantics, in that if the returned type isn't a pointer, it will call operator-> again on that type. But, the intermediate value is kept as a temporary by the calling expression. This allows code to detect changes in the returned value:
template<class T>
class wrapper
{
// ...
T val;
struct arrow_helper
{
arrow_helper(const T& temp)
: temp(temp){}
T temp;
T* operator->() { return &temp; }
~arrow_helper() { std::cout << "modified to " << temp << '\n'; }
};
arrow_helper operator->() { return{ val }; }
//return const value to prevent mistakes
const T operator*() const { return val; }
}
and then T's members can be accessed transparently:
wrapper<Foo> f(/*...*/);
f->bar = 6;
Is there anything that could go wrong from doing this? Also, is there a way to get this effect with functions other than operator->?
EDIT: Another issue I've come across is in expressions like
f->bar = f->bar + 6;
since when the arrow_helper from the second operator-> is destructed it re-overwrites the value back to the original. My semi-elegant solution is for arrow_helper to have a T orig that is hidden, and assert(orig == *owner) in the destructor.
There is no guarantee that all changes will be caught:
Foo &x = f->bar;
x = 6; /* undetected change */
If there is no way to grab a reference to any data within T through T's interface or otherwise, I think this should be safe. If there's any way to grab such a pointer or reference, you're done and in undefined behavior as soon as someone saves off such reference and uses it later.
Why is answer "OK"?
class CTest {
public:
int isitme(CTest& cobj);
};
int CTest::isitme(CTest &cobj)
{
if(&cobj == this)
{
return true;
}
else
{
return false;
}
}
int main()
{
CTest a;
CTest *b = &a;
if(b->isitme(a))
{
cout<<"OK";
}else
{
cout<<"not OK";
}
return 0;
}
Because a member function implicitly receives as an argument a pointer to the object it is invoked on. This pointer is made available within the body of the function as the this pointer.
So when you do:
b->isitme(a)
The member function isitme() implicitly receives the pointer b as an argument, and that pointer will be seen as the this pointer inside the function.
Since b points to a, this will point to a (after all, you are invoking the member function isitme() on object a through the pointer b).
Since a is what is being passed as an explicit argument, a is also what the reference cobj is bound to. Therefore, taking the address of cobj gives you the address of a. Which in turns mean, that the expression:
// Address of "a": "cobj" is bound to argument "a" in the function call
// vvvvv
&cobj == this
// ^^^^
// Address of "a": the function is called through a pointer to "a"
Evaluates to true.
The short answer is that b is a pointer to a -- they both refer to the same actual object, so when you compare those "two" objects' addresses, they compare equal.
There's something else that really needs to be pointed out, and although it's more comment than answer, it won't fit in a comment, so...
int CTest::isitme(CTest &cobj)
{
if(&cobj == this)
{
return true;
}
else
{
return false;
}
}
This is, quite honestly, pretty lousy code. Since it's really returning a bool, you should declare it to return a bool. It's also much better to directly return the result from the comparison. You should also do some reading about "const correctness". Taking those factors into account, your function ends up looking more like this:
bool CTest::isitme(CTest const &cobj) const {
return this == &cobj;
}
There are a couple of things going on here.
First, there is only one copy of CTest being allocated. To check this, you could put a print in the constructor:
class CTest {
public:
CTest() {
cout << "Constructor called";
}
...
};
If you then invoked your program, you'd see that the constructor was called only once.
When isitme is invoked, the this pointer is being compared to the address of the cobj parameter. Both are pointing to the same object, so they both contain the same memory address. Thus, the comparison passes.
The other thing to notice is that you are passing by reference. If you didn't pass by reference, then this would not work. For example, if you had the following code:
class CTest {
public:
...
bool isitme(CTest cobj) {
return this == &cobj;
}
};
Then the object would be passed by value. As a result, a copy of cobj is made. In fact, another constructor (the compiler provided default copy constructor) is called to make a new object which is a copy of the given one.
To prove this, override the default copy constructor to display a message.
class CTest {
public:
// Default constructor
CTest() {
cout << "Constructor called" << endl;
}
// Copy constructor
CTest(CTest& source) {
cout << "Copy constructor called" << endl;
}
// Comparison
bool isitme(CTest obj) {
return (this == &obj);
}
};
// Main program
int main (int argc, char* argv[]) {
...
CTest a;
CTest* b = &a;
cout << (b->isitme(a)) << endl;
...
}
Now if you run the program, you'd notice both constructors are called. The first time is during the constructor for a. The second time is when you pass a to the isitme method and it creates a copy.
When passed by value, the isitme check would fail because it is comparing the pointers (memory addresses) of two different objects.
int CTest::isitme(CTest &cobj)
{
// cobj is a reference, but still an object
CTest * pCobj = &cobj; //pCobj is now the pointer to the actual memory
//so it's the same as this pointer. Because you did before CTest *b = &a;
}
b is pointing a, then you are using a in
b->isitme(a)
the isitme() simply checks the object passed as parameter against this. In this case it is, so OK
1st code:
#include <iostream>
using namespace std;
class demo
{
int a;
public:
demo():a(9){}
demo& fun()//return type isdemo&
{
return *this;
}
};
int main()
{
demo obj;
obj.fun();
return 0;
}
2nd code:
#include <iostream>
using namespace std;
class demo
{
int a;
public:
demo():a(9){}
demo fun()//return type is demo
{
return *this;
}
};
int main()
{
demo obj;
obj.fun();
return 0;
}
what is the difference between these two codes as both are working in gcc?i am new here so forgive me if my way of asking is wrong.
demo & fun() returns a reference to the current object. demo fun() returns a new object, made by copying the current object.
Both are valid but are different. In the first case demo& fun() a reference to the same object is returned, in the second case a new object is created. While both are the same, the semantics differ, run this example:
#include <iostream>
struct test {
int x;
test() : x() {}
test& foo() { return *this; }
test bar() { return *this; }
void set( int value ) { x = value; }
};
int main() {
test t;
t.foo().set( 10 ); // modifies t
t.bar().set( 5 ); // modifies a copy of t
std::cout << t.x << std::endl; // prints 10
}
Apart from what #Erik said about the return type, a little excursus on the this-pointer:
The following is equivalent:
struct my_struct{
my_struct* get_this() const { return this; }
};
my_struct obj;
my_struct* obj_this = ob.get_this();
std::cout << std::boolalpha; // to display true/false instead of 1/0
std::cout << "&obj == obj_this = " << &obj == obj_this << "\n";
The this pointer is just the pointer to that object, you can think of it as a hidden parameter. It's more understandable in the C way:
typedef struct my_struct{
int data;
// little fidgeting to simulate member functions in c
typedef void (*my_struct_funcptr)(struct my_struct*,int);
my_struct_funcptr func;
}my_struct;
// C++ does something similar to pass the this-pointer of the object
void my_struct_func(my_struct* this, int n){
this->data += n;
}
my_struct obj;
obj.data = 55;
// see comment in struct
obj.func = &my_struct_func;
obj.func(&obj, 15);
// ^^^^ - the compiler automatically does this for you in C++
std::cout << obj.data; // displays 70
Consider your function.
demo fun(){return *this;}
Here you are returning by value so one temporary object will be created which will be destroyed, once you assign the return value of fun to some other object.
While in case when you pass the reference, no object will be created newly, but it will pass actual object and even after assigning function return value object will not destroy till main object(used inside fun, in ur case its the object calling the function) won't go out of scope.
The concept you are trying to understand can be explained in more detail with other example.
consider function that is taking object as argument and returning object as argument.(also consider we have object that contains a pointer, we will assign value to pointer by first allocating memory to pointer and a destructor, which will free memory hold by pointer of object). Now when you return object as pass by value, temporary object will be created, that will have exact copy of main object(and temporary object's pointer will also point to same address or you can say holds the same address). Now inside main(), you assign/initialize any object with return value(object) of function. But when your temp object will be destroyed after assigning value, it will also free the memory because of destructor and when you try to fetch the same address value through assigned object(inside main() ) you will get error as that memory has been already freed.
But if you would have return value using reference, object returned by object won't destroy as main obj(inside function or through which we have called the function) is in scope and your pointer won't loose its memory. Making possible for assigned object to fetch address value through its pointer and avoid undesirable result.
In code 1 demo obj creates a fresh copy of demo. obj is initialised using demo's default constructor 'demo():a(9){}'. obj.fun() returns a reference to (already existing) obj.
In code 2 obj.fun() creates a new demo type object using demo's copy constructor (in your case it is compiler generated) and returns that copy to the caller.
Both code are valid.
1st code fun() is returning a reference to current object
2nd code fun() is returning the copy (by value) of the object
For 1st case, If you decide to return by value
then prefer to return a const
reference; i.e. const demo& fun();
and later you can copy it if needed.
Simply returning reference makes the
object modifiable, which may
accidently edit the content without
intent
For 2nd case, Do NOT return the object by value,
because it can create unnecessary
temporary copy which will effect
the memory/performance of your code