Passing C++ Types as Reference using SWIFT_IMMORTAL_REFERENCE.

I have a Class defined in C++, I want to pass the instance of class from C++ to Swift as a reference type. By default swift maps C++ classes as value types but we can change this behavior by using SWIFT_IMMORTAL_REFERENCE annotation mentioned here. The example mentioned here is of Singelton class but I have a usecase where i require more than one instance.

Cpp Class Skeleton.

class Cpp {
    
public:
    
    
void Print () noexcept;
  
void SetValue (int pValue) noexcept;
    
// Method which is Invoked by Swift.

static Cpp& ReturnObj () noexcept;
 
private:
    int vValue;
} SWIFT_IMMORTAL_REFERENCE;

Definition of Return Obj

Cpp&
Cpp::ReturnObj () noexcept {
    
    static Cpp obj;
    
    return obj;
}

Swift Co

var obj : Cpp = Cpp.ReturnObj()
    
    withUnsafeBytes(of: &obj) {(pointer : UnsafeRawBufferPointer)  in
        print (pointer)
        print (pointer.baseAddress!)
    }

Output

Address Printed by C++ 0x100008000

Address Printed by Swift 0x00007ff7bfeff108

So from the above observation copy is passed.

How to do pass by reference then?

Answered by DTS Engineer in 803262022

Again, you’re missing really fundamental aspects of how Swift works. In your example, withUnsafeBytes(of: &obj) doesn’t yield the address of the object, it yields the address of the pointer. And that may not even be the actual pointer, because & is free to copy in and then copy out. I cover that in detail in The Peril of the Ampersand, which I linked to in my response on your previous thread.

Consider this code:

class MyClass {}

var o1 = MyClass()
var o2 = o1
withUnsafeBytes(of: &o1) { p in
    print(p.baseAddress!)               // 0x00000001000084f8
    withUnsafeBytes(of: &o2) { p in
        print(p.baseAddress!)           // 0x0000000100008500
    }
}

The addresses are different because they’re the addresses of o1 and o2 (or a copy thereof), not the address of the object itself.

The standard way to get the ‘address’ of an object is via ObjectIdentifier:

class MyClass {}

let o1 = MyClass()
let o2 = o1
print(ObjectIdentifier(o1))     // ObjectIdentifier(0x00006000006a00c0)
print(ObjectIdentifier(o2))     // ObjectIdentifier(0x00006000006a00c0)

ps I’m happy to keep answering your questions — I think it’s great to have an excuse to populate DevForums with a corpus of knowledge like this — but it might be more efficient for you to review some of the resources I’ve been pointing you at. The Peril of the Ampersand has some great talks you really need to watch. Additionally, I think you’d get a lot of value out of the Swift for C++ Practitioners series.

https://www.douggregor.net

The author is:

  • One of the architects of Swift

  • And has an extensive C++ background

That makes him very well qualified to explain this stuff.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Just a remark on the use of the forum. You may ask as many questions as needed, but you have to answer to replies you get to tell if that answers your question (and then close the thread) or if not explain in the same post what is the remaining issue.

Otherwise, developers on this forum may get tired to answer your repeated posts on very similar questions if they never receive a feedback.

Have a good day.

Again, you’re missing really fundamental aspects of how Swift works. In your example, withUnsafeBytes(of: &obj) doesn’t yield the address of the object, it yields the address of the pointer. And that may not even be the actual pointer, because & is free to copy in and then copy out. I cover that in detail in The Peril of the Ampersand, which I linked to in my response on your previous thread.

Consider this code:

class MyClass {}

var o1 = MyClass()
var o2 = o1
withUnsafeBytes(of: &o1) { p in
    print(p.baseAddress!)               // 0x00000001000084f8
    withUnsafeBytes(of: &o2) { p in
        print(p.baseAddress!)           // 0x0000000100008500
    }
}

The addresses are different because they’re the addresses of o1 and o2 (or a copy thereof), not the address of the object itself.

The standard way to get the ‘address’ of an object is via ObjectIdentifier:

class MyClass {}

let o1 = MyClass()
let o2 = o1
print(ObjectIdentifier(o1))     // ObjectIdentifier(0x00006000006a00c0)
print(ObjectIdentifier(o2))     // ObjectIdentifier(0x00006000006a00c0)

ps I’m happy to keep answering your questions — I think it’s great to have an excuse to populate DevForums with a corpus of knowledge like this — but it might be more efficient for you to review some of the resources I’ve been pointing you at. The Peril of the Ampersand has some great talks you really need to watch. Additionally, I think you’d get a lot of value out of the Swift for C++ Practitioners series.

https://www.douggregor.net

The author is:

  • One of the architects of Swift

  • And has an extensive C++ background

That makes him very well qualified to explain this stuff.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Passing C++ Types as Reference using SWIFT_IMMORTAL_REFERENCE.
 
 
Q