开发者

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

开发者 https://www.devze.com 2023-01-15 07:58 出处:网络
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.

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).


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...


The general rule with properties is, if you need specific behaviour that the default boilerplate that gets generated cannot provide you, write your own -setFoo: method for your foo property which does what you need it to. Automatic synthesis of properties are meant for the common case, they are not going to be applicable everywhere. In those cases, provide your own setter or getter for the property.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号