为什么我的结果数据返回为void *会被破坏?

时间:2016-10-19 07:53:10

标签: c++

我正在一个拥有庞大遗留代码库的项目中工作,并且一直试图重新设计它的一部分以摆脱旧的C风格代码。

我遇到了问题并准备了一个简短的程序来解释。

我正在使用的遗留接口需要我将指向结果数据的指针传递为void *,我希望避免更改此内容。

示例中的unique_ptr只是用于演示,在我的实际代码库中,处理数据的所有内容都使用智能指针来管理内存。

我的问题是,结果数据被破坏了(参见上一个输出行/最后一次调用printPayload);最后一切都是0,但是转换到void *并且如第2和第3个输出线所示,它似乎没有问题。

这是与临时相关的问题吗? 我不明白......

我希望这种问题与你们中的一些人有关。

#include <iostream>
#include <memory>

struct Payload
{
    long a;
    int b;
    int c;

    Payload() : a(), b(), c() {}
    Payload(long setA, int setB, int setC) : a(setA), b(setB), c(setC) {}
};

void printPayload(const Payload& printThis)
{
    std::cout << "payload -- a: " << printThis.a << " b: " << printThis.b << " c: " << printThis.c << std::endl;
}

void doSomething(Payload* sourceData, void* targetData)
{
    if (!sourceData) return;

    std::unique_ptr<Payload> sourceDataUnique(sourceData);

    sourceDataUnique->a = 222;
    sourceDataUnique->b = 333;
    sourceDataUnique->c = 444;

    printPayload(*sourceDataUnique);

    targetData = reinterpret_cast<void*>(sourceDataUnique.release());

    printPayload(*(reinterpret_cast<Payload*>(targetData)));
}

int main(void)
{
    Payload* myPayload = new Payload(14, 8, 1982);
    Payload myResult;

    printPayload(*myPayload);

    doSomething(myPayload, &myResult);

    printPayload(myResult);
}

输出:

payload -- a: 14 b: 8 c: 1982
payload -- a: 222 b: 333 c: 444
payload -- a: 222 b: 333 c: 444
payload -- a: 0 b: 0 c: 0

3 个答案:

答案 0 :(得分:8)

targetDatadoSomething本地变量。为其分配地址后,它将超出范围。

您永远不会真正分配给myResult

答案 1 :(得分:3)

在您的代码中,参数targetDatadoSomething函数的本地参数(即,退出函数范围后,任何更改都将丢失)。但是,*targetData是指myResult函数中声明的变量main

因此,以下代码应该有效:

void doSomething(Payload* sourceData, void* targetData)
{
    if (!sourceData) return;

    sourceData->a = 222;
    sourceData->b = 333;
    sourceData->c = 444;

    printPayload(*sourceData);

    Payload* td = static_cast<Payload*>(targetData);
    *td = *sourceData;
    printPayload(*td);
}

答案 2 :(得分:1)

您无法将源数据复制到目标,但只能更改targetData指针指向的对象。

这样的事情会起作用:

Payload* targetPayload = reinterpret_cast<Payload*>(targetData);
*targetPayload = *sourceData;

通过智能指针获取源有效负载的所有权可能是一个坏主意 - 如果编写调用代码以正确处理异常,那么它将在错误上删除对象,因此智能指针将意味着它被删除两次。如果没有编写调用代码来正确处理异常,那么编写无法抛出异常的代码是你的工作,而智能指针并没有帮助。

(因为它是指针之间的转换,你可以使用static_cast,但我更喜欢reinterpret_cast,因为void *可能是任何,reinterpret_cast告诉其他开发人员正在发生一些潜在的危险。)< / p>