2009-04-13 72 views
31

Tôi có std::vector với các yếu tố n. Bây giờ tôi cần chuyển một con trỏ tới một vectơ có các phần tử n-1 cuối cùng cho một hàm. Ví dụ: vector<int> foo chứa (5,2,6,87,251). Một hàm lấy vector<int>* và tôi muốn chuyển nó tới một con trỏ tới (2,6,87,251).Chuyển đổi trình vòng lặp thành con trỏ?

Tôi có thể chỉ (an toàn) lấy trình vòng lặp ++foo.begin(), chuyển đổi nó thành con trỏ và chuyển nó tới hàm này không? Hoặc sử dụng &foo[1]?

CẬP NHẬT: Mọi người đề nghị tôi thay đổi chức năng của mình để dùng trình lặp thay vì con trỏ. Điều đó dường như không thể xảy ra trong tình huống của tôi, vì hàm tôi đã đề cập là hàm find của unordered_set<std::vector*>. Vì vậy, trong trường hợp đó, đang sao chép các phần tử n-1 từ foo vào một vectơ mới và gọi số find bằng con trỏ đến tùy chọn duy nhất đó? Rất không hiệu quả! Nó giống như Shlemiel họa sĩ, đặc biệt là kể từ khi tôi phải truy vấn nhiều tập con: cuối cùng n-1, sau đó n-2, v.v ... và xem chúng có nằm trong unordered_set hay không.

+0

Bạn có thể giải thích thêm một chút về những gì bạn đang thực sự cố gắng làm không? Tôi hơi bối rối - có vẻ như bạn đang cố gắng làm điều gì đó với unordered_set <> và unordered_set <> :: find() rằng chúng không thực sự được thiết kế để làm (nhưng tôi hoàn toàn có thể không hiểu) . –

+0

Tại sao bạn sử dụng một vectơ để đại diện cho một tập hợp không có thứ tự ở vị trí đầu tiên? Nếu bạn đang thực hiện nhiều truy vấn thành viên, có nhiều triển khai hiệu quả hơn nhiều. Bạn có thể muốn tạo một bộ và sau đó truy vấn đối với nó. – Uri

+0

Tôi có một bộ S được biết đến trình tự. Đối với mỗi chuỗi mới, tôi phải tìm ra nhanh nếu nó ở trong S hay không. Tôi nhận ra rằng lưu trữ các trình tự đã biết như các vectơ riêng biệt và lưu trữ các con trỏ tới chúng trong unordered_set là một bộ nhớ lãng phí, và một trie sẽ tốt hơn. Nhưng tôi muốn tra cứu liên tục. – Frank

Trả lời

8

Điều đó dường như không thể xảy ra trong trường hợp của tôi, vì hàm tôi đã đề cập là hàm tìm kiếm của unordered_set<std::vector*>.

Bạn có đang sử dụng các đối tượng hàm băm/vị ngữ tùy chỉnh không? Nếu không, thì bạn phải vượt qua unordered_set<std::vector<int>*>::find() con trỏ tới vectơ chính xác mà bạn muốn tìm. Một con trỏ tới một vectơ khác có cùng nội dung sẽ không hoạt động. Điều này không phải là rất hữu ích cho tra cứu, để nói rằng ít nhất.

Sử dụng unordered_set<std::vector<int> > sẽ tốt hơn, vì sau đó bạn có thể thực hiện tra cứu theo giá trị. Tôi nghĩ rằng cũng sẽ yêu cầu một đối tượng hàm băm tùy chỉnh vì hash không theo kiến ​​thức của tôi có chuyên môn cho vector<int>.

Dù bằng cách nào, một con trỏ vào giữa một véc tơ không phải là chính nó là một vectơ, như những người khác đã giải thích. Bạn không thể chuyển đổi một trình vòng lặp thành con trỏ thành vectơ mà không sao chép nội dung của nó.

+0

Câu trả lời nhanh cho câu hỏi của bạn: Có, tôi đang sử dụng đối tượng vị ngữ tùy chỉnh quyết định xem hai vectơ có giống nhau hay không bằng cách so sánh các phần tử của chúng. (Hmm, tra cứu đó không phải là thời gian không đổi ...) – Frank

0

Nếu chức năng của bạn thực sự mất vector<int> * (con trỏ tới vectơ), thì bạn nên vượt qua &foo vì đó sẽ là con trỏ tới vectơ. Rõ ràng điều đó sẽ không đơn giản giải quyết vấn đề của bạn, nhưng bạn không thể trực tiếp chuyển đổi một trình lặp thành một vectơ, vì bộ nhớ tại địa chỉ của trình lặp sẽ không trực tiếp giải quyết một vectơ hợp lệ.

Bạn có thể xây dựng một vector mới bằng cách gọi vector constructor:

template <class InputIterator> vector(InputIterator, InputIterator) 

này xây dựng một vector mới bằng cách sao chép các yếu tố giữa hai vòng lặp. Bạn sẽ sử dụng nó gần như thế này:

bar(std::vector<int>(foo.begin()+1, foo.end()); 
+0

Nhưng điều đó sẽ truyền cho nó một con trỏ tới vectơ có nội dung (5,2,6,87,251), trong khi tôi muốn chuyển nó tới một vector với nội dung (2,6,87,251). – Frank

+0

Vâng tôi đã đọc sai câu hỏi. Tôi đã cập nhật với một số chi tiết mới cho một giải pháp có thể –

5

Nếu bạn có thể, lựa chọn tốt hơn có thể là thay đổi hàm để chuyển đổi thành phần tử hoặc vector mới (nếu không sửa đổi).

Trong khi bạn có thể thực hiện những điều này với mảng vì bạn biết cách chúng được lưu trữ, có thể là một ý tưởng tồi để làm tương tự với vectơ. &foo[1] không có loại vector<int>*.

Ngoài ra, trong khi triển khai STL có sẵn trực tuyến, thường mạo hiểm khi thử và dựa vào cấu trúc nội bộ của một trừu tượng.

+0

Cảm ơn nhận xét. Tôi đã trả lời ở trên trong bản cập nhật của mình. – Frank

3

Chức năng của bạn không được dùng vector<int>*; phải mất vector<int>::iterator hoặc vector<int>::const_iterator nếu thích hợp. Sau đó, chỉ cần vượt qua trong foo.begin() + 1.

1

Ví dụ: vector<int> foo chứa (5,2,6,87,251). Một hàm lấy vector<int>* và tôi muốn chuyển nó tới một con trỏ tới (2,6,87,251).

Con trỏ đến vector<int> không giống với con trỏ đến các phần tử của véc tơ.

Để thực hiện việc này, bạn sẽ cần phải tạo một vector<int> mới chỉ với các yếu tố bạn muốn trong đó để chuyển con trỏ đến. Một cái gì đó như:

vector<int> tempVector(foo.begin()+1, foo.end()); 

// now you can pass &tempVector to your function 

Tuy nhiên, nếu chức năng của bạn mất một con trỏ đến một mảng của int, sau đó bạn có thể vượt qua &foo[1].

2

Câu trả lời trực tiếp cho câu hỏi của bạn là có. Nếu foo là một vectơ, bạn có thể thực hiện điều này: & foo [1].

Tuy nhiên, điều này chỉ hoạt động đối với vectơ vì tiêu chuẩn cho biết rằng các vectơ thực hiện lưu trữ bằng cách sử dụng bộ nhớ phi thường.

Nhưng bạn vẫn có thể (và có lẽ nên) chuyển qua trình vòng lặp thay vì con trỏ thô vì nó mang tính biểu cảm hơn. Các trình vòng lặp truyền qua không tạo bản sao của vectơ.

+1

Tôi nghĩ & foo [1] sẽ là một mảng các số nguyên, không phải là một vector . Một vector biết chiều dài của nó. Có & foo [1] biết chiều dài của nó? –

+0

& foo [1] không biết chiều dài của nó, không. Và có, & foo [1] sẽ là một mảng ints. –

0

Tôi chưa thử nghiệm điều này nhưng thay vào đó bạn có thể sử dụng một tập hợp các cặp vòng lặp không? Mỗi cặp lặp sẽ đại diện cho trình vòng lặp bắt đầu và kết thúc của vectơ chuỗi. Ví dụ:

typedef std::vector<int> Seq; 
typedef std::pair<Seq::const_iterator, Seq::const_iterator> SeqRange; 

bool operator< (const SeqRange& lhs, const SeqRange& rhs) 
{ 
    Seq::const_iterator lhsNext = lhs.first; 
    Seq::const_iterator rhsNext = rhs.first; 

    while (lhsNext != lhs.second && rhsNext != rhs.second) 
     if (*lhsNext < *rhsNext) 
      return true; 
     else if (*lhsNext > *rhsNext) 
      return false; 

    return false; 
} 

typedef std::set<SeqRange, std::less<SeqRange> > SeqSet; 

Seq sequences; 

void test (const SeqSet& seqSet, const SeqRange& seq) 
{ 
    bool find = seqSet.find (seq) != seqSet.end(); 
    bool find2 = seqSet.find (SeqRange (seq.first + 1, seq.second)) != seqSet.end(); 
} 

Rõ ràng các vectơ phải được giữ ở nơi khác như trước đây. Ngoài ra nếu một vector trình tự được sửa đổi thì mục nhập của nó trong tập hợp sẽ phải được loại bỏ và thêm lại khi các trình vòng lặp có thể đã thay đổi.

Jon

3

Vectơ là một vùng chứa có toàn quyền sở hữu các yếu tố của nó. Một vectơ không thể giữ một phần của khung nhìn khác, thậm chí là một khung nhìn const. Đó là nguyên nhân gốc rễ ở đây.

Nếu bạn cần, hãy tạo vùng chứa của riêng bạn có chế độ xem với dữ liệu của weak_ptr hoặc xem phạm vi. Cặp các trình vòng lặp (thậm chí các con trỏ hoạt động tốt như các trình vòng lặp thành một vectơ) hoặc, thậm chí tốt hơn, tăng :: iterator_range hoạt động khá liền mạch.

Tùy thuộc vào khả năng tem của mã của bạn. Sử dụng std :: pair nếu bạn cần ẩn mã trong cpp.

62

đây nó được, lấy một tham chiếu đến con trỏ coresponding của việc sử dụng iterator:

dụ:

string my_str= "hello world"; 

string::iterator it(my_str.begin()); 

char* pointer_inside_buffer=&(*it); //<-- 

[thông báo điều hành * trả về một tham chiếu làm như vậy & trên một tài liệu tham khảo sẽ cho bạn địa chỉ].

+11

điều gì sẽ xảy ra khi trình vòng lặp trỏ tới '' 'my_str.end()' ''? Con trỏ có trỏ đến địa chỉ không hợp lệ trong chuỗi không? – Unglued

+5

@Unglued: Nếu bạn cố gắng tham chiếu 'my_str.end()', một phiên bản trình gỡ lỗi sẽ ném một lệnh xác nhận "" chuỗi lặp không phải là dereferencable "' và phiên bản phát hành sẽ ném một ngoại lệ. – ahmd0

1

Sử dụng vector::front, nó phải là giải pháp di động nhất. Tôi đã sử dụng điều này khi tôi đang giao tiếp với một API cố định mà muốn có một ptr char. Ví dụ:

void funcThatTakesCharPtr(char* start, size_t size); 

... 

void myFunc(vector<char>& myVec) 
{ 
    // Get a pointer to the front element of my vector: 
    char* myDataPtr = &(myVec.front()); 

    // Pass that pointer to my external API: 
    funcThatTakesCharPtr(myDataPtr, myVec.size()); 
} 
0

Vector là một lớp học mẫu và nó không phải là an toàn để chuyển đổi các nội dung của một lớp học để một con trỏ: Bạn không thể kế thừa lớp vector để thêm chức năng mới này. và thay đổi tham số chức năng thực sự là một ý tưởng tốt hơn. Jst tạo một vectơ khác của int vector temp_foo (foo.begin [X], foo.end()); và chuyển vector này cho bạn chức năng

0

Phiên bản an toàn để chuyển đổi trình lặp thành con trỏ (chính xác là điều gì có nghĩa là không phụ thuộc vào ý nghĩa) và an toàn tôi có nghĩa là không phải lo lắng về việc lặp lại biến tần và gây ra ngoại lệ lỗi do end()/tình huống khác

#include <iostream> 
#include <vector> 
#include <string.h> 

int main() 
{ 
    std::vector<int> vec; 

    char itPtr[25]; 
    long long itPtrDec; 

    std::vector<int>::iterator it = vec.begin(); 
    memset(&itPtr, 0, 25); 
    sprintf(itPtr, "%llu", it); 
    itPtrDec = atoll(itPtr); 
    printf("it = 0x%X\n", itPtrDec); 

    vec.push_back(123); 
    it = vec.begin(); 
    memset(&itPtr, 0, 25); 
    sprintf(itPtr, "%llu", it); 
    itPtrDec = atoll(itPtr); 
    printf("it = 0x%X\n", itPtrDec); 
} 

sẽ in cái gì đó như

nó = 0x0

it = 0x2202E10

Đó là một cách vô cùng khó khăn để làm điều đó, nhưng nếu bạn cần, nó sẽ thực hiện công việc. Bạn sẽ nhận được một số cảnh báo trình biên dịch, nếu thực sự làm phiền bạn, có thể bị xóa bằng #pragma

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