Pass by value on with a copy constructor?

M

Marcel Müller

My compiler (gcc 3.3.5) complains to have no copy constructor for C in
the code below.

Is it really true that function arguments can only be supplied by the
copy constructor and not any other constructor?

By the way, a by far older compiler from IBM Visual Age 3.0 eats it.


Marcel


class C
{private:
C(const C&);
void operator=(const C&);
public:
C(int);
};

void foo(C c)
{
}

int main()
{ foo(7);
}
 
J

Jorgen Grahn

My compiler (gcc 3.3.5) complains to have no copy constructor for C in
the code below.

Is it really true that function arguments can only be supplied by the
copy constructor and not any other constructor?

Which other constructor would that be? The only one you have is C(int).
By the way, a by far older compiler from IBM Visual Age 3.0 eats it.

A much newer compiler also fails the code. Your gcc is clearly right.
class C
{private:
C(const C&);
void operator=(const C&);
public:
C(int);
};

void foo(C c)
{
}

int main()
{ foo(7);
}

Foo needs a C, and it cannot just make one up -- it has to be a copy of
a C provided by the caller. You have forbidden anything which can
"duplicate" a C, so there is no way for it to do the copying it
requests.

(There may be more exact ways of explaining it, but that's how I think
of the problem.)

/Jorgen
 
M

Marcel Müller

Gcc is correct. You are passing C to foo() by value, which logically
requires an (accessible) copy ctor. Visual Age probably optimized this
step away without a warrant.

To avoid this pass-by-value step and get your code compiling, declare the
foo() function as:

void foo(const C& c);

I know, although it must not be const in my case.

But C is a scoped smart pointer (RAII idiom), which cannot be copied. It
has a memory footprint of one pointer. Using a reference would add
another level of indirection to each access in foo.
OK, I won't die of that in this application. But I would like to avoid
it if possible. And I do not like the auto_ptr hack to make it copyable.

Constructors without any arguments would not be very useful, would they?
;-)

Well, the constructor from int fits well in my case.

I understand, that pass by value requires a constructor invocation. But
is it necessarily the copy constructor?

I hope it has been fixed since then.

Probably not. It has been discontinued years ago.


Marcel
 
S

SG

Am 08.11.2012 22:37, schrieb Marcel Müller:
My compiler (gcc 3.3.5) complains to have no copy constructor for C in
the code below.

Is it really true that function arguments can only be supplied by the
copy constructor and not any other constructor?

class C
{private:
C(const C&);
void operator=(const C&);
public:
C(int);
};

void foo(C c)
{
}

int main()
{ foo(7);
}

The kind of initialization for function parameters is "copy
initialization". This is exactly the same kind of initialization like in
the following code fragment:

C object = 7; // copy initialization

For this initialization, the C++ standard requires the target type to be
copyable even in the case of a compiler being smart enough to elide the
copy as per copy elision rules.

So, yes, your compiler rejecting this code is totally fine.

Cheers!
SG
 
S

SG

Am 08.11.2012 23:29, schrieb Paavo Helde:
To avoid this pass-by-value step and get your code compiling, declare the
foo() function as:

void foo(const C& c);

Actually, with the class 'C' having a private copy ctor, you can't
initialize this reference with an rvalue in C++98 and C++03 because the
reference initialization rules require C to be copyable in such a case.
In C++11, however, this has been relaxed.

I know about this issue because of the following little article:
http://pizer.wordpress.com/2009/03/25/

Cheers!
SG
 
R

Richard Damon

But C is a scoped smart pointer (RAII idiom), which cannot be copied. It
has a memory footprint of one pointer. Using a reference would add
another level of indirection to each access in foo.
OK, I won't die of that in this application. But I would like to avoid
it if possible. And I do not like the auto_ptr hack to make it copyable.

Marcel

Think what you are asking the language to do. You have a object in the
caller that you defined that it can not be copied, but you want a copy
of it to be in the called function (that is what pass by value means).

References are one way to do this, but that will tend to cause the extra
level of indirection.

Other options would be making C more like a shared pointer, so it is
copyable, or you could just make the called function take the raw
pointer. If the caller "owns" the pointer, than the called function
doesn't need any life time control on the pointer, so it doesn't need to
be smart.
 
M

Marcel Müller

or you could just make the called function take the raw
pointer.

This was my first approach.
If the caller "owns" the pointer, than the called function
doesn't need any life time control on the pointer, so it doesn't need to
be smart.

Unfortunately the underlying C API has some circumstances when the
object must not be freed. (Whoever designed this crap.) So I wanted to
change it in the way I showed in the OP.

In fact I ended up by passing the unmanaged raw pointer and moved the
wrapper class to a local variable in the callee. The only disadvantage
is, that the raw pointer must not be used directly by the callee. Since
it is a shared memory pointer it will result in a crash before the
wrapper class has done it's work.


Marcel
 
M

Marcel Müller

It appears that you actually want a local scoped variable to be created
in a larger scope (outside of the function) and to be released in a
smaller scope (inside the function). Does not sound very consistent to
me.

You are absolutely right. Unfortunately the underlying C-API requires
some cases where only parts of the resources must not be freed. This is
the source of the problem and not very consistent either. (It's a drag &
drop API with source rendering.)
I know almost no application which implements this correctly in all
cases. So using drag & drop heavily causes the shared memory to decrease
slowly. After several thousand drag & drop operations the shared memory
usually gets low. No real problem as long as you reboot daily. But
otherwise it's annoying.

However, I ended up with your suggestion with a local manager class. It
is not perfect, but it will do the job as long as I avoid direct access
to the pointer in the callee.


Marcel
 
M

Marcel Müller

The kind of initialization for function parameters is "copy
initialization". This is exactly the same kind of initialization like in
the following code fragment:

C object = 7; // copy initialization

For this initialization, the C++ standard requires the target type to be
copyable even in the case of a compiler being smart enough to elide the
copy as per copy elision rules.

So, yes, your compiler rejecting this code is totally fine.

You mentioned in your other posting that this has been relaxed by C++11.
So, is the above statement only true before C++11?
(Of course, my compiler does not support C++11.)


Marcel
 
S

SG

Am 10.11.2012 10:14, schrieb Marcel Müller:
You mentioned in your other posting that this has been relaxed by C++11.

What has been relaxed is the initialization of references not to require
copyable types anymore.
So, is the above statement only true before C++11?

My statement you quoted here applies to every version of C++.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,961
Messages
2,570,131
Members
46,689
Latest member
liammiller

Latest Threads

Top