0

Well I have a small question to solve a matter of mine (and maybe some others ^^). So let's assume the following in C++ :

class A {
  public:
    A() { }
    A(const A& src) { }
};

class B {
  public:
    B() { }
    void foo(A valuePassing) { }
};

int main(int argc, char* argv[])
{
    A passed;
    B obj;

    obj.foo(passed);        

    return EXIT_SUCCESS;
}

In this code, who is responsible of calling A's copy constructor? The question could be generalized : when passing by value, who is responsible of the copy of the variable, the caller or the callee? In that specific case, will B call the copy constructor when receiving the var or is it main() which will call it and send the copy over to B's method?

My first thought is that, to maintain the protection induced by C++ accesibilities, it should be the caller doing the copy job. But I need to be sure of it. And is it common to every compiler (don't see why not but differences between compilers are sometimes so weird)? Namely VC++ and gcc.

Thanks in advance for your answers ;)

Edit:
If anyone wonders, this is about implementing the Pass Key pattern created by Georg Fritzsche. Indeed, as some stated, making it non-copyable is a good idea to prevent not too smart developers from making a function that gives the key to anyone from the class that is granted the key. But making it non-copyable also prevents standard value argument passing (at least it should, I have found out that Visual C++ compiler does not follow the standard and is actually ok with that...)

My idea to solve the problem is to create a base PassKey class that has protected copy constructor and assignment operator. Then every PassKey classes will inherit from this one. Then the function that require the key to be used ask as first parameter the key by value. This way even if a smartass developer do the previously mentioned function and gives a reference to the key, the external class that will try to use it won't be able to because it needs access to the key's copy constructor which is accessible only to the protected and granted classes.

Was I clear enough or do that need some clarification? :S

Community
  • 1
  • 1
Jeremy B.
  • 73
  • 9
  • 2
    Would the difference have any observable effect? Surely all that matters is that at some point, a copy gets made. – Oliver Charlesworth Jul 16 '14 at 12:00
  • 3
    what do you mean by "who"? The compiler inserts a call to the copy constructor in the context of `main`. Arguments have to be initialized before the function is invoked. – Jonathan Wakely Jul 16 '14 at 12:01
  • 2
    I suppose the calling code *caused* the copy to occur by calling the function and passing `passed`, but asking what is "responsible" for it doesn't really make sense. If anything, the initialization of the argument is responsible for it. – Joseph Mansfield Jul 16 '14 at 12:05
  • The question is complicated by inlining, in this specific code there might not even _be_ a "call" to `B::foo`. The copy might still happen, but how do you say "who" did it, if the function is inlined? – Jonathan Wakely Jul 16 '14 at 12:14
  • neither the caller nor the calle. The compiler. All praise the compiler – bolov Jul 16 '14 at 12:19
  • By who is responsible I meant who called it of course. I thought it to be obvious sorry :S Should I change the title? What I mean is if the copy constructor is protected it can still be called by children or friends. But in the case of passing the class by value, which results in a copy, who calls the constructor? I believe that would be the caller but I'm not sure as I said. Still some people seem to agree ^^ So I'll try. @OliCharlesworth That makes a HUGE difference, specifically because of the copy constructor accessibility ;) – Jeremy B. Jul 16 '14 at 12:24

3 Answers3

2

obj.foo(passed); will result in the following sequence of steps, generated by a compiler:

  1. Put obj's pointer onto stack frame (the this parameter)
  2. Create a temp variable (this is where the copy constructor is being called)
  3. Put that temp onto stack frame
  4. Make a call to foo()
  5. Once returned from the function - clear up the stack (this is where the destructor is called)
YePhIcK
  • 5,816
  • 2
  • 27
  • 52
  • Is this guaranteed by the C++ standard? – Oliver Charlesworth Jul 16 '14 at 12:05
  • Not in standard, this is the "usual" implementation – YePhIcK Jul 16 '14 at 12:07
  • 1
    The creation of the temporary & use of copy-initialization is guaranteed according to the rules in §8.5.3. – Michael Foukarakis Jul 16 '14 at 12:25
  • Oh wow thanks @MichaelFoukarakis. You mean that it is guaranteed by the standard that the caller of a function/method will call the copy constructors of the variables sent to the function by value? (in this case main will call the copy constructor of `A` to copy `passed` and give the copy to `B.foo`?) – Jeremy B. Jul 16 '14 at 12:38
  • In this case, it is. See [this question](http://stackoverflow.com/questions/1826934/copy-constructor-needed-with-temp-object) and answers for more information. – Michael Foukarakis Jul 16 '14 at 12:49
  • @MichaelFoukarakis Well from what I read on that other topic, VC9 already didn't give a damn about copy-ctors accessibility :P Well anyway thank you for all the information that really helps, hopefully I can get my rep up and comment on the topic I mentioned in the question if I can make the PassKey pattern fully protected. – Jeremy B. Jul 16 '14 at 12:58
  • Accepted this answer because it is understandable and because @MichaelFoukarakis actually found a reference to this in the standard, so this is now something guaranteed. Thanks everyone for all the tips! Oh also I just realized in your answer YePhIcK, if I understand correctly, it is also the caller's scope that calls the destructor right? – Jeremy B. Aug 01 '14 at 10:00
0

Now I'll answer as general as I am able.

The short answer is that it is your compiler's job to call the constructor. It will as far as I know also be constructed by the caller. Exactly how this is done, however, may depend on the calling convention you are using.

There exists a number of calling conventions, one compiler may support more than one, see for instance this page at MSDN. And different architectures may demand a specific convention.

For x86, one calling convention would be like YePhIck answered, whilst on for instance on an ARM platform, the address would be placed directly in a register before the branch to the function. And not pushed to the stack (unless you have more than 4 parameters).

Can it ever be the callee's responsibility to copy the object? I'm not aware of such a calling convention, but it might exist.

Stian Svedenborg
  • 1,797
  • 11
  • 27
  • Yeah just checked I use the cdecl as my calling convention (I remember configuring that because I didn't want to use the default VC++ calling convention because of a particular feature, can't remember which). What matters is that it is the caller that calls the copy constructor so thanks ;) – Jeremy B. Jul 16 '14 at 12:28
  • Out of curiosity, why does it matter? – Stian Svedenborg Jul 16 '14 at 12:36
  • Ah, just read your edit, so the question is really: Will this protected constructor be in scope when function X is called... – Stian Svedenborg Jul 16 '14 at 12:39
  • Yes, the intent being that the constructor hopefully is not called by the callee function since that would completely break the security of the PassKey pattern ;) But if @MichaelFoukarakis confirms that it is part of the standard then the PassKey would not only be more human-readable than the Attorney-Client idiom but also a bit more safe! – Jeremy B. Jul 16 '14 at 12:41
  • Wanted to vote up but my rep doesn't allow it =/ Why participating doesn't count toward rep :( Yeah well anyway, I vote you up in comments :D – Jeremy B. Jul 16 '14 at 14:03
0

Well, how class B can invoke a function by itself? You have just two places for copy constructor calling: main() and foo(). And I can't see any calls from foo, so the answer is obvious. And don't forget about return type of foo().

Hvarnah
  • 141
  • 6
  • Woops sorry about foo's type, was a sample :S Well since the call is not explicit I just wanted to be sure. The call is done implicitly during the execution of the foo method ;) – Jeremy B. Jul 16 '14 at 12:53