2016-10-19 16 views
6

Tôi đang làm việc trong một dự án với một cơ sở mã di sản khổng lồ và đã cố gắng thiết kế lại các bộ phận của nó để thoát khỏi mã c-style cũ.Tại sao dữ liệu kết quả của tôi bị trả về là void * bị hỏng?

Tôi đã gặp sự cố và đã chuẩn bị một chương trình ngắn để giải thích.

Giao diện cũ mà tôi đang sử dụng cần tôi chuyển con trỏ đến dữ liệu kết quả là void * và tôi muốn tránh phải thay đổi điều này.

Unique_ptr trong ví dụ minh họa, trong cơ sở mã thực sự của tôi, mọi thứ hoạt động trên dữ liệu đều sử dụng con trỏ thông minh để quản lý bộ nhớ.

Vấn đề của tôi là dữ liệu kết quả bị hỏng (xem dòng đầu ra cuối cùng/cuộc gọi cuối cùng để printPayload); tất cả mọi thứ là 0 ở cuối, nhưng nó không có vẻ là một vấn đề với chuyển đổi để void * và trở lại như được hiển thị bởi dòng đầu ra thứ 2 và thứ 3.

Đây có phải là sự cố liên quan đến thời gian không? Tôi không nhận được ...

Tôi hy vọng loại vấn đề này có liên quan đến một số bạn.

#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); 
} 

Output:

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 
+0

Bạn đặt 'targetData' trong 'doSomething', nhưng thay đổi này là cục bộ cho hàm. Tham số phải là tham chiếu. –

+0

Điều này có thể được đơn giản hóa thành: 'void doSomething (Payload * src, Payload * dst) {dst = src; } ' – melpomene

+0

@PankajDaga, sẽ không hoạt động, vì nó sẽ là tham chiếu đến tạm thời. – StoryTeller

Trả lời

8

targetData là một biến địa phương-doSomething. Sau khi bạn gán một địa chỉ cho nó, nó sẽ nằm ngoài phạm vi.

Bạn chưa bao giờ thực sự gán cho myResult.

3

Trong mã của bạn, tham số targetData là địa phương để doSomething chức năng (tức là, bất kỳ thay đổi nào bị mất sau khi bạn thoát khỏi phạm vi chức năng). Tuy nhiên, *targetData là biến số myResult được khai báo trong hàm main.

Vì vậy, các mã sau đây nên làm việc:

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); 
} 
+0

@melpomene tất nhiên. Đó là một lỗi đánh máy. Sửa đổi nguồn. Cảm ơn. –

+0

@JonathanWakely yes, tôi chỉ muốn giữ chức năng tương tự như mã gốc. Sửa đổi nguồn. –

1

Bạn đừng bao giờ sao chép dữ liệu nguồn tới đích, nhưng chỉ thay đổi đối tượng mà con trỏ trỏ targetData tới.

Something như thế này sẽ làm việc:

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

Lấy quyền sở hữu của tải trọng nguồn qua một con trỏ thông minh có lẽ là một ý tưởng tồi - nếu mã gọi được viết để xử lý ngoại lệ chính xác, sau đó nó sẽ xóa các đối tượng trên một lỗi, do đó, con trỏ thông minh sẽ có nghĩa là nó bị xóa hai lần. Nếu mã gọi không được viết để xử lý các ngoại lệ một cách chính xác, thì đó là công việc của bạn để viết mã mà không thể ném một ngoại lệ, mà con trỏ thông minh không hỗ trợ.

(vì nó là một dàn diễn viên giữa con trỏ, bạn có thể sử dụng static_cast, nhưng tôi thích reinterpret_cast như void * có thể là bất cứ điều gì và reinterpret_cast nói với các nhà phát triển khác một cái gì đó nguy hiểm tiềm tàng đang xảy ra.)

Các vấn đề liên quan