make_unique的例外情况:为什么f(new T)异常是安全的

时间:2015-05-29 00:58:54

标签: c++ exception c++14 exception-safety

我一直在阅读GOTW102,并且想知道为什么class VideoMediaViewController: NSViewController { weak var mainView : DTMainViewController? @IBOutlet weak var aVPlayerView: AVPlayerView! var url:NSURL?{ didSet{ // this is the setter } } var observer:AnyObject? var player:AVPlayer? var videoOutput:AVPlayerItemVideoOutput? var ciContext:CIContext? var loadStatus:NSNumber? override func viewDidLoad() { aVPlayerView.controlsStyle = AVPlayerViewControlsStyle.None } func loadMedia() { unloadMedia() //Create AVPlayerItem player = AVPlayer.playerWithURL(url) as? AVPlayer //Create VideoOutput videoOutput = AVPlayerItemVideoOutput(pixelBufferAttributes: [kCVPixelBufferPixelFormatTypeKey:kCVPixelFormatType_32ARGB]) //Get notifications for status player?.addObserver(self, forKeyPath: "status", options:.New, context: nil) //looping logic start player?.actionAtItemEnd = AVPlayerActionAtItemEnd.None NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerItemDidReachEnd:", name: AVPlayerItemDidPlayToEndTimeNotification, object: player?.currentItem) //looping logic end observer = player?.addPeriodicTimeObserverForInterval(CMTimeMake(150, 600), queue: dispatch_get_main_queue(), usingBlock: {[unowned self](CMTime) in self.updateSliderProgress() self.updateStartAndEndTimes() }) //Set videoOutput to player player?.currentItem.addOutput(videoOutput) aVPlayerView.player = player aVPlayerView.player.play() } func playerItemDidReachEnd(notification: NSNotification) { let aVPlayerItem: AVPlayerItem = notification.object as! AVPlayerItem aVPlayerItem.seekToTime(kCMTimeZero) } func scrubberSliderChanged(sender: AnyObject){ var duration:Float64 = CMTimeGetSeconds(player!.currentItem.duration) var sliderValue:Float64 = Float64(mainView!.scrubberSlider!.floatValue) var seekToTime = CMTimeMakeWithSeconds(((sliderValue * duration)/100.00), 1) player?.seekToTime(seekToTime, completionHandler: { (Bool) -> Void in }) } func secondsToHoursMinutesSeconds (seconds : Int) -> (Int, Int, Int) { return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60) } func getStringFromHoursMinutesSeconds(h:Int, m:Int, s:Int) -> (String){ let formatter = NSNumberFormatter() formatter.minimumIntegerDigits = 2 let hours = formatter.stringFromNumber(h) //"00" let minutes = formatter.stringFromNumber(m) //"01" let seconds = formatter.stringFromNumber(s) //"10" var timerString = hours! + ":" + minutes! + ":" + seconds! return timerString } func updateStartAndEndTimes(){ var time = CMTimeGetSeconds(player!.currentItem.duration) - CMTimeGetSeconds(player!.currentItem.currentTime()) var (hours,minutes,seconds) = secondsToHoursMinutesSeconds(Int(time)) let timeRemainingString = getStringFromHoursMinutesSeconds(hours, m: minutes, s: seconds) mainView!.videoTimeRemaing.stringValue = timeRemainingString time = CMTimeGetSeconds(player!.currentItem.currentTime()) (hours,minutes,seconds) = secondsToHoursMinutesSeconds(Int(time)) let timePassedString = getStringFromHoursMinutesSeconds(hours, m: minutes, s: seconds) mainView?.videoTimePassed.stringValue = timePassedString // mainView!.videoTimeRemaing.stringValue = "\(CMTimeGetSeconds(player!.currentItem.duration) - CMTimeGetSeconds(player!.currentItem.currentTime()))!" // mainView?.videoTimePassed.stringValue = "\(CMTimeGetSeconds(player!.currentItem.currentTime()))!" } func updateSliderProgress(){ var currentTime = CMTimeGetSeconds(player!.currentItem.currentTime()) var duration = CMTimeGetSeconds(player!.currentItem.duration) var progress = currentTime/duration*100 mainView!.scrubberSlider!.doubleValue = progress } func unloadMedia() { //Cancel Prerolls and Notifications player?.cancelPendingPrerolls player?.removeTimeObserver(observer) player?.removeObserver(self, forKeyPath: "status") NSNotificationCenter.defaultCenter().removeObserver(self, name: AVPlayerItemDidPlayToEndTimeNotification, object: nil) //dispose of assets and players, etc //... } override func viewWillDisappear() { unloadMedia() } //Get Status updates and log success or failure override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) { if ( (object as! NSObject) == player && keyPath == "status") { if (player?.status == .ReadyToPlay) { NSLog("Status - Loaded") } else if (player?.status == .Failed) { NSLog("Status - Failed") } else { NSLog("Status - Unknown") } } } 比其他情况更安全,或详细说明为什么make_uniquef(new T(...))更安全。

博客中的f(new T1(...), new T2(...))实施内容如下:

make_unique

现在我想知道template<typename T, typename ...Args> std::unique_ptr<T> make_unique( Args&& ...args ) { return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) ); } 是否一般异常安全(无泄漏),或者f(new T(...))是否只是异常安全,因为{{1}的构造函数增加了知识不扔? (根据我的理解,无论如何,新建的make_unique都会被泄露。

1 个答案:

答案 0 :(得分:10)

原因是在函数调用或类似函数中,参数不会引发序列点(不是“之前排序”)。例如:

do_work(unique_ptr<A>(new A), unique_ptr<B>(new B));

允许编译器生成如下代码:

  1. new A
  2. new B //可能会扔!
  3. 构建unique_ptr<A>
  4. 构建unique_ptr<B>
  5. 致电do_work
  6. 如果new B抛弃,那么您已泄露了A,因为没有构建unique_ptr

    unique_ptr构造放入其自己的函数中可以消除此问题,因为不允许编译器同时执行函数体(因此“new”和“construct unique_ptr步骤需要一起完成)。

    即,给定:

    do_work(make_unique<A>(), make_unique<B>())
    

    编译器必须生成如下代码:

    1. 致电make_unique<A>
    2. 致电make_unique<B>
    3. 致电do_work
      1. 致电make_unique<B>
      2. 致电make_unique<A>
      3. 致电do_work
      4. 在新的对象浮动的情况下进行泄漏而不能拥有unique_ptr