2016-05-27 20 views
5

Tôi hiện đang cố gắng gọi hàm thư viện sqlite3, và nó hy vọng tôi chuyển nó qua số sqlite3**.Đưa con trỏ đến một đối tượng được trỏ tới bởi con trỏ thông minh - Lỗi Ivalue

Đây là mã hiện tại của tôi. Tôi có một phần làm việc, và một phần đó mang lại cho tôi một lỗi:

sqlite3 *sqlite = m_db.get(); 
if (sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &sqlite)) 
{ 

} 

if (sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &(m_db.get()))) 
{ 

} 

lĩnh vực m_db của tôi trông như thế này:

std::unique_ptr<sqlite3> m_db = nullptr; 

Trong hai ví dụ tôi hiển thị, người đầu tiên được làm việc hoàn toàn tốt đẹp . Tuy nhiên, thứ hai mang lại cho tôi lỗi này. Lưu ý rằng đây là đến từ phần &(m_db.get()):

“Address expression must be an lvalue or a function designator” 

Tôi đọc lên một chút về lvalues ​​và rvalues, nhưng tôi dường như không thể tìm ra lý do tại sao cú pháp này sẽ không thực hiện được. Theo như tôi hiểu bây giờ, vấn đề là giá trị trả về của hoạt động .get() chỉ đơn thuần là một kết quả biểu thức tạm thời, và do đó không có vị trí nhận dạng trong bộ nhớ mà tôi có thể lấy địa chỉ từ đó.

Có một cách để đạt được điều này trong một tuyên bố, tôi đoán vậy.

Bất cứ ai có thể giải thích cho tôi lý do tại sao tính năng này không hoạt động và cách tôi có thể khắc phục?

+0

tại sao bạn làm những thứ lạ với 'm_dbName' –

+0

Đó là một wstring tôi đang chuyển đổi thành một chuỗi – Sossenbinder

+0

Đó là khá tinh ranh –

Trả lời

8

Toán tử & chỉ có thể được sử dụng với một giá trị (hoặc có id đủ điều kiện khi thực hiện con trỏ đến thành viên). Biểu thức m_db.get() là một giá trị vì nó trả về một con trỏ theo giá trị, không phải bằng tham chiếu, do đó bạn không thể lấy địa chỉ của nó.

unique_ptr không cung cấp phương thức truy cập con trỏ cơ bản dưới dạng tham chiếu, bạn sẽ cần lưu trữ bản sao ở đâu đó như trong ví dụ đầu tiên của bạn.

+0

Và lý do nó sẽ không cho phép bạn truy cập vào con trỏ nằm bên dưới là 'unique_ptr' phải thực hiện một số công việc nếu bạn chỉ định một giá trị mới (cụ thể, gọi deleter trên giá trị cũ). Nó không thể làm được điều đó nếu bạn chỉ cần đi vào dưới bìa và gán cho con trỏ bên dưới. –

1

There has to be a way to achieve this in one statement, I guess.

Tôi không hoàn toàn chắc chắn về điều đó; điểm về giá trị tạm thời thực sự có thể là phải mất một tuyên bố để có được một vĩnh viễn.

Ngoài ra, bạn đang rối tung với ngữ nghĩa của con trỏ thông minh, mà bạn không nên làm - .get thực sự không nên được sử dụng ở đây.

Soooo, những gì tôi muốn làm là dựa vào C++ phạm vi ở đây, và không quan tâm đến thực tế là tôi tuyên bố một con trỏ "bình thường" đầu tiên để tạo một con trỏ thông minh sau này.

your_class::initialize_db() { 
    sqlite3 *sqlite; 
    int retval = sqlite3_open(std::string(m_dbName.begin(), m_dbName.end()).c_str(), &sqlite); 
    if(retval == SQLITE_OK) 
     m_db = std::unique_ptr<sqlite3>(sqlite); 

} 
+0

Lưu ý rằng sqlite phải được đóng ngay cả khi mở không thành công: '" Có hay không một lỗi xảy ra khi nó được mở, tài nguyên liên quan đến xử lý kết nối cơ sở dữ liệu sẽ được giải phóng bằng cách chuyển nó tới sqlite3_close() khi nó không còn cần thiết nữa. " ', do đó, nên tạo unique_ptr bất kể. (Nhưng nó cũng cần một deleter tùy chỉnh như đã đề cập ở nơi khác.) – Zitrax

3

Con trỏ thông minh lưu một con trỏ và trả về khi nhận. Những gì bạn muốn làm ở đây là ngược lại: bạn có được một con trỏ từ sqlite3_open và muốn lưu trữ nó trong một con trỏ thông minh. Vì vậy, bạn sẽ làm điều gì đó như

sqlite3* db = nullptr; 
sqlite3_open(..., &db); 
m_db.reset(db); 

Khi tính năng chính của unique_ptr là để xóa các con trỏ chứa trong destructor của nó, tôi không chắc chắn nếu nó làm cho tinh thần để sử dụng nó ở đây. Theo như tôi hiểu nó, bạn có nghĩa vụ phải gọi sqlite3_close trên con trỏ trả về, không xóa nó.

+1

Bạn có thể cung cấp cho [deleters tùy chỉnh] (http://stackoverflow.com/questions/19053351/how-do-i-use-a-custom-deleter-with- a-stdunique-ptr-member) vào 'unique_ptr'. sẽ gọi một hàm khác thay vì 'xóa'. (Nhưng tốt hơn hết là không nên sử dụng unique_ptr ở đây, như bạn nói). –

+0

Vâng, đó là sự thật. Tôi đã thay đổi điều đó ngay sau khi tôi phát hiện ra nó hoạt động như thế nào với sqlite3. Tuy nhiên, tôi muốn hỏi câu hỏi này, không bao giờ đau khổ khi học hỏi điều gì đó hơn bạn cần. – Sossenbinder

1

Một giá trị cơ bản là thứ gì đó có thể xuất hiện ở phía bên tay trái của toán tử gán. Vì vậy, lỗi nói rằng bạn chỉ có thể truy xuất địa chỉ của thứ gì đó có thể được gán cho hoặc chức năng.Nó sẽ có tác dụng nếu bạn có quyền truy cập thành viên vào con trỏ sqlite3 * bên trong unique_ptr, nhưng bạn không, và vì lý do chính đáng.

Thêm vào vấn đề này, bạn không nên sử dụng con trỏ thông minh trong trường hợp này. Nếu sqlite3_open yêu cầu một đối số sqlite3 **, thì điều đó có nghĩa là hàm sẽ cung cấp một giá trị cho con trỏ sqlite3 *. Về cơ bản nó là một mẫu thông số out C# hoặc các ngôn ngữ khác. Nó sẽ được rõ ràng hơn cho nó được cung cấp như là một kết quả chức năng, nhưng điều đó đã bị lấy đi bởi mã kết quả. Đây là tất cả tốt và tốt, nhưng con trỏ thông minh muốn có quyền kiểm soát giá trị này. Bạn đặt giá trị một lần lúc khởi tạo, nhưng sau đó, con trỏ thông minh sẽ xử lý nó. Và nó cần phải làm điều này để duy trì những hạn chế của nó: tính duy nhất của quyền sở hữu, deallocation khi con trỏ tự nó đi ra khỏi phạm vi vv. Nếu bạn về cơ bản đi và ghi đè lên con trỏ sqlite3 * bên trong, thì điều đó không thể xảy ra nữa, bởi vì con trỏ thông minh không có cách nào để chặn ghi đè và xử lý đối tượng mà nó hiện đang sử dụng.

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