Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy Constructor not called by synthesized property setter in Objective C++ code

We all know how sparsely documented Objective-C++ is. I can't find anything on this, but I'm also finding it hard to find suitable unambiguous search terms. So, Stackoverflow to the rescue (I hope)!

I have a C++ class that I have an instance of within an Objective-C(++) class (and I have the project setting enabled for constructors/ destructors to be called).

This all works fine until I try to expose the instance via a @synthesized property. I make it an assign property (as Obj-C retain counting is not applicable). The property appears to work except when I set the instance I would expect the copy constructor to be involved. What I actually see is that a temporary instance is created (the copy constructor on that is invoked) - which is all expected. But the copy constructor on the ivar instance is not called. The values are "magically" set. I'm presuming that the @synthesized code is doing something like a memcpy as the final step. This is fine for C structs, but not so helpful for C++ classes where the correctness of the code depends on the copy constructors and assignment operators being called appropriately.

Has anyone looked into this in any more depth, got it working, or confirmed that it is not possible to hold C++ objects as ivars in an Obj-C(++) class and have copy constructors called by @synthesized property setters?

(I can post sample code for all this if necessary - but even the minimal version is a screenful or so).

like image 712
philsquared Avatar asked Sep 04 '10 16:09

philsquared


1 Answers

Uhm, if I'm not confused, it's perfectly reasonable that the copy constructor is not called. Do you expect that ivar to be magically destructed and copy-constructed? I guess that's against C++'s rules. If the synthesized setter is conceptually

-(void)setFoo:(Foo)foo_{
    foo=foo_;
}

then operator= should be called, rather than the copy constructor.

That said, the operator= is not called either, bummer (10.6.4, gcc 4.2.1.)! Here's the sample code:

#import <Foundation/Foundation.h>

class Foo{
    int a,b;
public:
    Foo():a(0),b(0){NSLog(@"default constructor for %p",this);}
    Foo(const Foo&foo):a(foo.a),b(foo.b){NSLog(@"copy constructor for %p",this);}
    Foo& operator=(const Foo& foo){
    NSLog(@"assignment operator for %p",this);
        a=foo.a;
        b=foo.b;
        return *this;
    }
};

@interface Bar:NSObject {
    Foo foo;
}
@property (assign) Foo foo;
@end

@implementation Bar
@synthesize foo;
@end

int main(){
    NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
    Bar* bar=[[Bar alloc] init];
    Foo foo;
    bar.foo=foo;
    [pool drain];
}

Save it into boo.mm, I had:

$ g++ -fobjc-call-cxx-cdtors boo.mm -framework Foundation
$ ./a.out
2010-09-04 12:32:06.570 a.out[24352:903] default constructor for 0x10010cdc8
2010-09-04 12:32:06.572 a.out[24352:903] default constructor for 0x7fff5fbff7e0
2010-09-04 12:32:06.573 a.out[24352:903] copy constructor for 0x7fff5fbff7d0
$

Now, I had the explicit setter I wrote above instead of @synthesize Foo, I correctly had

$ ./a.out
2010-09-04 12:42:22.206 a.out[24417:903] default constructor for 0x10010cdc8
2010-09-04 12:42:22.209 a.out[24417:903] default constructor for 0x7fff5fbff7e0
2010-09-04 12:42:22.210 a.out[24417:903] copy constructor for 0x7fff5fbff7d0
2010-09-04 12:42:22.210 a.out[24417:903] assignment operator for 0x10010cdc8

The clang source code for the generation of the synthesized setter is this, see GenerateObjCSetter. There, it eventually tests whether C++ assignment operator is needed. I would say it's a gray area, not well-documented but currently being implemented...

like image 147
Yuji Avatar answered Sep 23 '22 14:09

Yuji