2017-05-16 12 views
0

私はDockerコンテナでSwift 3とZeroMQを使用しています。拡張機能を介してZeroMQ.Messageにいくつかの便利な初期化子を追加したいと思います。私が現在持っていることは、コンパイラをクラッシュさ:ZeroMQメッセージの迅速なイニシャライザでコンパイラがクラッシュする

import Foundation 
import ZeroMQ 
import SwiftProtobuf 

extension ZeroMQ.Message { 
    convenience init?(string: String, encoding: String.Encoding = .utf8) { 
     var asData = string.data(using:encoding)! 

     asData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in 
      let unsafe = UnsafeMutableRawPointer.allocate(bytes: asData.count, alignedTo: 8) 
      unsafe.copyBytes(from: bytes, count: asData.count) 
      try? self.init(data: unsafe, size: asData.count) 
     } 
    } 

    convenience init?(protobuf: SwiftProtobuf.Message) { 
     guard let data = try? protobuf.serializedData() else { 
      return nil 
     } 

     data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in 
      let unsafe = UnsafeMutableRawPointer.allocate(bytes: data.count, alignedTo: 8) 
      unsafe.copyBytes(from: bytes, count: data.count) 
      try? self.init(data: unsafe, size: data.count) 
     } 
    } 
} 

私は、これは非常に多く、「ディープ・エンドでの中」の場合であるとして、何か間違ったことをやっていることは非常に高い可能性がある実現します。

コンパイルエラーが(可読性の利益のためにいくつかの手動行折り返しで)です:

Compile Swift Module 'src' (3 sources) 
swift: /home/buildnode/disk2/workspace/oss-swift-3.1-package-linux-ubuntu-16_04/swift/ 
    ... lib/SILGen/ManagedValue.h:202: 
    ... swift::SILValue swift::Lowering::ManagedValue::getLValueAddress() const: 
Assertion `isLValue() && "This isn't an lvalue"' failed. 

0 swift   0x000000000362f718 
1 swift   0x000000000362fe56 
2 libpthread.so.0 0x00007fd55e321390 
3 libc.so.6  0x00007fd55cc87428 gsignal + 56 
4 libc.so.6  0x00007fd55cc8902a abort + 362 
5 libc.so.6  0x00007fd55cc7fbd7 
6 libc.so.6  0x00007fd55cc7fc82 
7 swift   0x0000000000b5fbfc 
8 swift   0x0000000000b55ccc 
9 swift   0x0000000000b9c0bd 
10 swift   0x0000000000b9be2e 
11 swift   0x0000000000b6af32 
12 swift   0x0000000000b1f8f2 
13 swift   0x0000000000b61607 
14 swift   0x0000000000b572ab 
15 swift   0x0000000000b5579c 
16 swift   0x0000000000b5d73a 
17 swift   0x0000000000b5921a 
18 swift   0x0000000000b51c94 
19 swift   0x0000000000bc95eb 
20 swift   0x0000000000bc4cb1 
21 swift   0x0000000000bc4018 
22 swift   0x0000000000baea2d 
23 swift   0x0000000000bacefd 
24 swift   0x0000000000b57284 
25 swift   0x0000000000b55ccc 
26 swift   0x0000000000b9c0bd 
27 swift   0x0000000000b9be2e 
28 swift   0x0000000000b3720f 
29 swift   0x0000000000b26dba 
30 swift   0x0000000000b1f099 
31 swift   0x0000000000ba28d8 
32 swift   0x0000000000ba180b 
33 swift   0x0000000000ba17ce 
34 swift   0x0000000000b23dcb 
35 swift   0x0000000000b24dbb 
36 swift   0x0000000000b25415 
37 swift   0x000000000047f43d 
38 swift   0x000000000043b277 
39 libc.so.6  0x00007fd55cc72830 __libc_start_main + 240 
40 swift   0x00000000004386b9 
Stack dump: 
0. Program arguments: /usr/bin/swift -frontend ... 
1. While silgen constructor initializer SIL function @_TFE3srcC6ZeroMQ7MessagecfT6stringSS8encodingVE10FoundationSS8Encoding_GSqS1__ 
    for 'init' at /app/Simple/Sources/extensions.swift:24:17 
2. While silgen closureexpr SIL function @_TFFE3srcC6ZeroMQ7MessagecFT6stringSS8encodingVE10FoundationSS8Encoding_GSqS1__U_FGSPVs5UInt8_T_ 
    for expression at [/app/Simple/Sources/extensions.swift:27:33 - line:31:9] 
    RangeText="{ (bytes: UnsafePointer<UInt8>) in 
      let unsafe = UnsafeMutableRawPointer.allocate(bytes: asData.count, alignedTo: 8) 
      unsafe.copyBytes(from: bytes, count: asData!.count) 
      try? self.init(data: unsafe, size: asData!.count) 
     }" 
<unknown>:0: error: unable to execute command: Aborted 

同様のコードが、Factory Methodパターンを、次のことは結構ですので、私はこの問題は、使用中であることを信じていますtry?の指定された初期化子への呼び出し。

編集: 末尾の閉鎖のうち、self.init(...)を引くための代替的アプローチ:

convenience init?(string: String, encoding: String.Encoding = .utf8) { 
    guard let data = string.data(using:encoding) else { 
     return nil 
    } 

    let unsafe = UnsafeMutableRawPointer.allocate(bytes: data.count, alignedTo: 8) 

    data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in 
     unsafe.copyBytes(from: bytes, count: data.count) 
    } 
    do { 
     try self.init(data: unsafe, size: data.count) 
    } catch { 
     unsafe.deallocate(bytes: data.count, alignedTo: 8) 
    } 
} 

上記は、私は理解していないエラーが得られます。

交換
extensions.swift:41:17: error: 'self' used inside 'catch' block reachable from self.init call 
    convenience init?(string: String, encoding: String.Encoding = .utf8) { 

do { ... } catch { ... }は1つのライナーでコンパイラを満たしますが、初期化子がスローした場合にバッファをリークします(ZeroMQは成功のメモリを所有します)。ケース:

try? self.init(data: unsafe, size: data.count) 

答えて

0

私がZeroMQ APIに精通していないことが、間違った経路を下り、不必要に複雑になってしまったということが判明しました。 ZeroMQはすでにunsafeMutableBytes側面をカプセル化する方法があります。

public func send(_ data: Data, mode: SendMode = []) throws -> Bool 

...私はProtobufsはZeroMQのSocketに些細な拡張メソッドを追加した送信の利便性を向上させることが私の目標を達成するために行うために必要なので、すべてを:

extension Socket { 
    func send(_ proto: SwiftProtobuf.Message, mode: SendMode = []) throws -> Bool { 
     let data = try proto.serializedData() 
     return try self.send(data, mode: mode) 
    } 
} 
関連する問題