使用unique_ptr处理线路上的数据

时间:2017-10-03 20:04:48

标签: c++11 pointers unique

当在线上接收数据并将其发送到上层应用程序时,通常以C风格,我们有一个结构,例如带有void *:

Microsoft Forms 2.0 Object Library

稍后在代码中,在错误检查和mallocating之后,......,我们可以做一些事情:

Option Explicit
Dim DObj

Sub TestClipboard()
    Dim ClipData
    VerifyArchitecture
    If Not InitClipboardObject Then
        Terminate "Unable to initialize the clipboard object"
    ElseIf Not ClipboardPaste(ClipData) Then
        Terminate "Unable to retrieve the clipboard data"
    End If

    ' The message box will have the current clipboard text (if any exist)
    MsgBox "The clipboard contains the following text:" & _
    vbCrLf & vbCrLf & ClipData
    ClipData = "Text we put in the clipboard"
    ' However, this function will not succeed.
    If Not ClipboardCopy(ClipData) Then Terminate "Unable to put data into the clipboard"
End Sub

Function InitClipboardObject()
    On Error Resume Next
    ' If the code is run in VBA, the following reference library
    ' can be used as an alternative to late binding:
    '   Microsoft Forms 2.0 Object Library
    '       Note:  The reference library will not show up on the
    '       list unless a userform has already been added in Excel.
    '       If not, browse for the FM20.DLL file
    Set DObj = GetObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
    InitClipboardObject = Err = 0
End Function

' Put data in the clipboard similar to pressing Ctrl + C
Function ClipboardCopy(ByVal Data)
    On Error Resume Next
    DObj.SetText Data
    ' This line of code will throw the following error
    '   Error Number: -2147221008 (800401F0)
    '   Description: DataObject:PutInClipboard CoInitialize has not been called.
    ' However, it works perfectly in VBA
    DObj.PutInClipboard
    ClipboardCopy = Err = 0
End Function

' Retrieve data from the clipboard similar to pressing Ctrl + V
Function ClipboardPaste(ByRef Data)
    On Error Resume Next
    DObj.GetFromClipboard
    Data = DObj.GetText(1)
    ClipboardPaste = Err = 0
End Function

' This sub will re-load the script using the 32 bit host
' if it is loaded on the 64 bit version.  This is necessary
' since the clipboard object is 32 bit.
Sub VerifyArchitecture()
    ' The code in this sub is a modified version of Vozzie's answer
    ' and I do not take credit for the idea:
    '   https://stackoverflow.com/a/15320768/2734431
    Dim Arch, Arg, Args, Cmd, ExeFullName, ExeShortName
    Dim Path32, Path64, ProcEnv, q, Reload, ScriptName
    Dim WinDir, WShell
    q = Chr(34)
    Reload = False
    ExeFullName = WScript.FullName
    ScriptName = WScript.ScriptFullName
    ExeShortName = Mid(ExeFullName, InStrRev(ExeFullName, "\") + 1)
    Set WShell = CreateObject("WScript.Shell")
    Set ProcEnv = WShell.Environment("Process")
    WinDir = ProcEnv("windir") & "\"
    Path32 = WinDir & "SysWOW64\"
    Path64 = WinDir & "System32\"
    Arch = ProcEnv("PROCESSOR_ARCHITECTURE")

    For Each Arg In WScript.Arguments
        Args = " " & q & Arg & q
    Next
    Cmd = q & Path32 & ExeShortName & q & " " & q & ScriptName & q & Args
    If InStr(LCase(ExeFullName), LCase(Path64)) <> 0 And Arch = "AMD64" Then
        Reload = True
        WShell.Run Cmd
    End If

    Set WShell = Nothing
    Set ProcEnv = Nothing
    If Reload Then Terminate ""
End Sub

' This sub is designed to clear any global variables, optionally
' display an error message, and stop the script
Sub Terminate(ByVal ErrMsg)
    Dim ErrNbr
    Set DObj = Nothing
    If ErrMsg <> "" Then
        ErrNbr = "Error"
        If Err <> 0 Then
            ErrNbr = ErrNbr & " " & Err & " (" & Hex(Err) & ")"
            ErrMsg = ErrMsg & vbCrLf & vbCrLf
            ErrMsg = ErrMsg & "Code Error: " & Err.Description
        End If
        ' &H10 = vbCritical
        MsgBox ErrMsg, &H10, ErrNbr
    End If
    WScript.Quit
End Sub

在C ++中,尝试使用unique_ptr在以下代码段中失败:

struct SData{
//... len, size, version, msg type, ...
void* payload;
}

但是如你所知,这将导致:

if(msgType == type1){
    struct SType1* ptr = (struct SType1*) SData->payload;
}

有没有办法使用智能指针来处理这个?

我找到的一个解决方案是: Should std::unique_ptr<void> be permitted

这需要创建自定义删除器:

struct SData{
// .. len, size, version, msg type, ...
std::unique_ptr<void> payload;
}

使用

error: static assertion failed: can't delete pointer to incomplete type

这将需要更多的额外代码(与简单的不安全C风格相比),因为对于每种类型的有效负载,都必须添加一些逻辑。

1 个答案:

答案 0 :(得分:1)

  

这将需要更多的额外代码(与简单的不安全C风格相比),因为对于每种类型的有效负载,都必须添加一些逻辑。

额外的复杂性只是调用添加的析构函数。您可以使用函数指针而不是std::function,因为不应该使用闭包状态。

如果您不想要析构函数,只想将RAII添加到C语言中,那么请使用自定义删除工具,它只需operator deletestd::free