Thread: Temporary object return

  1. #16
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by Elysia View Post
    But if you use a move constructor, all you'd basically have to do is assign the pointer from the temporary vector to the new vector, set the temporary pointer to nullptr and update various member variables.

    I could implement a simple example of that, but I didn't feel that was necessary. Just knowing it invokes the move constructor should tell us that it's cheaper in execution time.
    If I understand correctly, you can't assume move semantics are implemented for you, even on primitives. So, this is what I was getting at, since the move copy constructor is lacking anything appropriate.

  2. #17
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    This would be more of a real world example:
    Code:
    #include "stdafx.h"
    #include <iostream>
    #include <utility>
    #include <ctime>
    #include <cstdlib>
    
    class A
    {
    public:
    	A(int n) 
    	{
    		std::cout << "A: Constructing...\n";
    		m_n = n;
    		m_p = new int[1000];
    	}
    	A(A& rhs)
    	{
    		std::cout << "A: Copy constructing...\n";
    		m_p = new int[1000];
    		std::copy(rhs.m_p, rhs.m_p + 1000, m_p);
    		m_n = rhs.m_n;
    	}
    	A(A&& rhs)
    	{
    		std::cout << "A: Move constructing...\n";
    		m_p = rhs.m_p;
    		rhs.m_p = nullptr;
    		m_n = rhs.m_n;
    	}
    	~A() 
    	{
    		std::cout << "A: Destructing...\n";
    		delete [] m_p;
    	}
    
    	int m_n;
    	int* m_p;
    };
    
    A&& foo()
    {
    	static A test(std::rand());
    	return std::move(test);
    }
    
    A bar()
    {
    	A test(std::rand());
    	return test;
    }
    
    int main()
    {
    	std::srand(std::time(nullptr));
    
    	{
    		std::cout << "Test with foo:\n";
    		A tmp = foo();
    		std::cout << "Result: " << tmp.m_n << std::endl;
    	}
    	{
    		std::cout << "\nTest with bar:\n";
    		A tmp = bar();
    		std::cout << "Result: " << tmp.m_n << std::endl;
    	}
    	{
    		std::cout << "\nTest with foo (r-ref):\n";
    		A&& tmp = foo();
    		std::cout << "Result: " << tmp.m_n << std::endl;
    	}
    	{
    		std::cout << "\nTest with bar (r-ref):\n";
    		A&& tmp = bar();
    		std::cout << "Result: " << tmp.m_n << std::endl;
    	}
    }
    Constructors now do something useful.
    (Although if this isn't optimized out by the compiler isn't certain; yet it is only there for demonstration and has no real point, so that's fine.)
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #18
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    you can certainly invoke the move semantics with any kind of return, but only a returned pointer or reference of some sort will eliminate the extra copy operation.
    The mechanism of "move semantics" in place doesn't say "you don't have to copy this datum an extra time". What has been in place is a means to distinguish between a call to a copying operation and a call to a moving operation. The point of "r-value references" is to allow "destructive copies".

    All of the attempts you are making to circumvent the copy operation, in the face of C++11 and "move semantics", is flawed because the overloaded constructor determines the best course of action. This determination is made at the best possible point. That is why "move semantics" for C++ is such a big deal. You don't need to allocate space for an object and return a pointer. You don't have to return a smart pointer. You don't need to make the object static. (These are "okay" alternatives, but they have consequences.) Other alternatives are manually activated move semantics, or variations on "pimpl". These are all options that existed before C++11.

    If the object represents a, naively determined, expensive to copy object the possibility of copying only a few primitives around instead represents the supposed benefit, but that's hardly the end of it. (That's not nearly as often the case as some would have you believe.) The benefit comes when the constructor, copy constructor, move constructor, and destruction are written with that possibility in mind. With the chosen "move semantics", you don't even need to fully construct a temporary; you only need to put the object to be destroyed in a state that the destructor can quickly deal with. Further, with a little work, you can make every "lifetime" operation but a couple of constructors and one path in the destructor use only primitive operations which can't fail by definition.

    Soma

  4. #19
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Constructors now do something useful.
    And a perfect example of why programmers shouldn't trivialize functions returning references to local variable even if made static.

    This line

    Code:
    A tmp = foo();
    effectively destroys the `foo::test' `A' instance.

    Soma

  5. #20
    Registered User
    Join Date
    Jul 2011
    Posts
    22
    Thank you very much for all your posts, 19 posts in such a short time. I am not too sure what happened with my code when I was testing it for the supposed "incorrect case" as laserlight pointed out. I was getting a NULL object as a result for one of my tests, but I probably did some simple mistake like using "Str&" as the return type. Laserlight also mentioned the possibility of using the "<<" operator, which I commonly use, but am a little confused on how to implement such an overload without editing the Str library's file.

    But what also seems interesting is the copy and move constructors. I have never run across those before, but they seem pretty interesting. I am assuming that each class have a built in default mover/copier? Or am I mistaken? The only way I did copying in the past was to overload the operator= to do my own little copying method.

    Thanks again for all the great support.
    Last edited by jakebird451; 08-31-2011 at 05:16 PM. Reason: changed to actual post count

  6. #21
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Code:
    A&& foo()
    {
    	static A test(std::rand());
    	return std::move(test);
    }
    This function is also horribly broken.

    1) If your test program shows two different values from foo, that's because your constructors don't initialize the data members. Foo always returns A with the same random value, unlike bar.

    2) It also says that the function is done with the instance `test` and is happy if you decide to move from it (i.e leaving it in an unspecified state). Which means that only the first invocation may have a meaningful result.

    E.g, if the result is used like this:
    Code:
    A a = foo();
    then it invokes the move constructor which is free to invalidate the right-hand object (foo::test).

    Code:
    A& foo()
    {
    	static A test(std::rand());
    	return test;
    }
    This should be the correct way (except that rand is called just once). The inclusion of rvalue references doesn't mean that normal references suddenly stop doing their job.

    Nor does it mean that you should abuse rvalue references for performance, sacrificing code correctness.
    Last edited by anon; 09-01-2011 at 01:02 AM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  7. #22
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by jakebird451 View Post
    But what also seems interesting is the copy and move constructors. I have never run across those before, but they seem pretty interesting. I am assuming that each class have a built in default mover/copier? Or am I mistaken? The only way I did copying in the past was to overload the operator= to do my own little copying method.
    All classes have a default copy constructor. No move constructor, however, AFAIK (how can the compiler know how to properly move resources?).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #23
    The larch
    Join Date
    May 2006
    Posts
    3,573
    If I'm not mistaken, you get default move constructors under certain conditions: no user-defined copy constructor + no user-defined destructor + all members are movable, or something like that. (This has been rather volatile in the drafts, I think.)
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Temporary object created by calling constructor
    By Eman in forum C++ Programming
    Replies: 18
    Last Post: 12-21-2010, 01:19 PM
  2. How do I return a temporary result object?
    By matsp in forum C++ Programming
    Replies: 4
    Last Post: 07-24-2007, 04:41 PM
  3. Temporary object debacle
    By verbity in forum C++ Programming
    Replies: 3
    Last Post: 04-24-2007, 11:37 PM
  4. Temporary object destruction
    By Mortissus in forum C++ Programming
    Replies: 2
    Last Post: 07-05-2006, 06:47 AM
  5. returning a temporary class object
    By nextus in forum C++ Programming
    Replies: 3
    Last Post: 01-31-2003, 03:54 PM

Tags for this Thread