0

I'm not sure how to translate C++ std::unique_ptr::swap into Go.

I am using std::unique_ptr<T,Deleter>::swap in C++:

std::unique_ptr<bool[]> maskA{new bool[num]};
std::unique_ptr<bool[]> maskB{new bool[num]};

// ...

maskA.swap(maskB); // Swap operation

Would I be missing something if I just use a simple maskA, maskB = maskB, maskA in Go?

maskA := make([]bool, num)
maskB := make([]bool, num)

// ...

maskA, maskB = maskB, maskA

Does this swap have the same functionality?

Marc
  • 19,394
  • 6
  • 47
  • 51
Megidd
  • 7,089
  • 6
  • 65
  • 142
  • "*I want to double-check*" Double-check what? That `swap` does what it says it does? – Nicol Bolas Jul 25 '20 at 04:51
  • @NicolBolas Double-checking whether `maskA, maskB = maskB, maskA` does the same thing as `std::unique_ptr::swap`, or am I missing something? – Megidd Jul 25 '20 at 04:54
  • C++ `std::unique_ptr::swap` is a different beast: `Exchanges the contents of the unique_ptr object with those of x, transferring ownership of any managed object between them without destroying either.` and has nothing to do with Go. You need to be more clear on what you are asking here. in Go swap is just a swap and like simple swap in C++: `temp=a; a=b; b=temp;` just in one line: `a, b = b, a` – wasmup Jul 25 '20 at 04:57
  • @user3405291: So your question has nothing to do with `unique_ptr`, and is really just asking whether C++ allows you to swap things (not just `unique_ptr`s) the way Go does. You should edit and rephrase your question to make that clear. – Nicol Bolas Jul 25 '20 at 05:02
  • 3
    You're comparing a basic shorthand feature of Go with a utility to handle pointer ownership in C++. These are completely unrelated. But yes, the code you showed will do the same thing, it's just that Go does not need pointer ownership utilities since it is a garbage collected language. – Marc Jul 25 '20 at 05:57
  • @Marc Thanks =) I posted your comment as answer before this question is closed. If you post your comment as answer, I will delete mine and will accept yours as the solution. – Megidd Jul 25 '20 at 08:20
  • 1
    I've written an answer with a lot more details. Please read it carefully. – Marc Jul 25 '20 at 09:16
  • @Marc Sure :) Thanks =) – Megidd Jul 25 '20 at 14:32

1 Answers1

2

The short answer:

This will be equivalent in terms of functionality but the actual performance implications are different. Use *[]bool for nearest equivalent.

Properties:

The assignment with exchange has the following properties:

  • the values of maskA and maskB will be exchanged
  • because these are slices, the underlying array of bools is not copied
  • thanks to compiler optimizations, the slice descriptors might not be copied either

The last two points are important and due to the way slices are built: they are small descriptors pointing to the underlying array. See slice internals for more details.

Differences between C++ and Go:

In C++, a unique_ptr<foo> always holds a *foo and the swap just involves exchanging addresses, this has predictable performance implications.

In Go, the type is whatever you give it, and the compiler will copy values. The amount of work depends on the type:

  • If these are big (eg: arrays: [1000]bool) it could get expensive
  • If they are slices as you have now (eg: []bool), the slice descriptor will be copied.
  • If they are pointers (eg: *[]bool), this will be the same as C++

So to be guaranteed equivalency to the C++ code, you should be using a pointer to a bool slice (*[]bool) as your Go types.

Go optimizations:

The Go compiler will try to optimize away the variable swap.

Here is a trivial example:

func main() {
  a := make([]bool, 0)
  b := make([]bool, 0)
  fmt.Println(a, b)
  a, b = b, a
  fmt.Println(a, b)
}

We can dump the optimization steps during compilation using GOSSAFUNC=main go build .

Looking at the resulting ssa.html file, we can see that the a, b = b, a line is dropped entirely and the following code is changed to something like fmt.Println(b, a).

When this happens your swap becomes just coding nicety and has no performance implications, but this will not always be the case (compiler optimizations are very specialized, there are cases where it cannot do this. eg: swapping two struct field members cannot be optimized away).

Unequal comparison:

Comparing the two is a little bit strange. A closer equivalent in C++ would be two plain variables to be swapped (whether pointers or not). The main goal of a unique_ptr is to simplify object ownership and delete the underlying object when the unique_ptr goes out of scope.

Go has no equivalent to unique_ptr mostly because it does not need to, all memory is garbage collected.

Marc
  • 19,394
  • 6
  • 47
  • 51