Làm thế nào đến một tham chiếu không const có thể liên kết với một đối tượng tạm thời?


226

Tại sao nó không được phép lấy tham chiếu non-const đến một đối tượng tạm thời, hàm nào getx()trả về? Rõ ràng, điều này bị cấm bởi C ++ Standard nhưng tôi quan tâm đến mục đích hạn chế đó, không phải là tài liệu tham khảo về tiêu chuẩn.

struct X
{
    X& ref() { return *this; }
};

X getx() { return X();}

void g(X & x) {}    

int f()
{
    const X& x = getx(); // OK
    X& x = getx(); // error
    X& x = getx().ref(); // OK
    g(getx()); //error
    g(getx().ref()); //OK
    return 0;
}
  1. Rõ ràng là thời gian tồn tại của đối tượng không thể là nguyên nhân, bởi vì tham chiếu liên tục đến một đối tượng không bị cấm theo Tiêu chuẩn C ++.
  2. Rõ ràng là đối tượng tạm thời không phải là hằng số trong mẫu ở trên, vì các lệnh gọi đến các hàm không hằng được cho phép. Ví dụ, ref()có thể sửa đổi các đối tượng tạm thời.
  3. Ngoài ra, ref()cho phép bạn đánh lừa trình biên dịch và nhận liên kết đến đối tượng tạm thời này và điều đó giải quyết vấn đề của chúng tôi.

Ngoài ra:

Họ nói rằng "việc gán một đối tượng tạm thời cho tham chiếu const kéo dài thời gian tồn tại của đối tượng này" và "Mặc dù vậy không có gì được nói về các tham chiếu không phải const". Câu hỏi bổ sung của tôi . Việc chuyển nhượng sau có kéo dài thời gian tồn tại của đối tượng tạm thời không?

X& x = getx().ref(); // OK

4
Tôi không đồng ý với phần "thời gian tồn tại của đối tượng không thể là nguyên nhân", chỉ vì nó được nêu trong tiêu chuẩn, việc gán một đối tượng tạm thời cho tham chiếu const kéo dài thời gian tồn tại của đối tượng này đến thời gian tồn tại của tham chiếu const. Không có gì được nói về các tài liệu tham khảo không liên tục mặc dù ...
SadSido

3
Chà, nguyên nhân của điều đó "Không có gì được nói về các tài liệu tham khảo không phải mặc dù ...". Đó là một phần câu hỏi của tôi. Có bất kỳ sence trong này? Có thể các tác giả của Standard chỉ quên các tài liệu tham khảo không liên quan và chúng ta sẽ sớm thấy Vấn đề cốt lõi tiếp theo?
Alexey Malistov

2
GotW # 88: Ứng cử viên cho "const quan trọng nhất". Herbutter.spaces.live.com/blog/cns!2D4327CC297151BB!378.entry
fnieto - Fernando Nieto

4
@Michael: VC liên kết các giá trị với các tham chiếu không phải là const. Họ gọi đây là một tính năng, nhưng thực sự đó là một lỗi. (Lưu ý rằng đó không phải là lỗi vì nó vốn đã phi logic, nhưng vì nó được loại trừ rõ ràng để ngăn chặn các lỗi ngớ ngẩn.)
sbi

Câu trả lời:


97

Từ bài viết trên blog Visual C ++ này về các tài liệu tham khảo về giá trị :

... C ++ không muốn bạn vô tình sửa đổi tạm thời, nhưng gọi trực tiếp một hàm không phải thành viên theo giá trị có thể sửa đổi là rõ ràng, vì vậy nó được phép ...

Về cơ bản, bạn không nên cố gắng sửa đổi tạm thời vì lý do chúng là đối tượng tạm thời và sẽ chết bất cứ lúc nào. Lý do bạn được phép gọi các phương thức không phải là vì, tốt, bạn được hoan nghênh làm một số điều "ngu ngốc" miễn là bạn biết bạn đang làm gì và bạn rõ ràng về nó (như, sử dụng reinterpret_cast). Nhưng nếu bạn liên kết tạm thời với một tham chiếu không phải là const, bạn có thể tiếp tục chuyển nó xung quanh "mãi mãi" chỉ để thao tác của đối tượng biến mất, bởi vì ở đâu đó trên đường bạn hoàn toàn quên mất đây là tạm thời.

Nếu tôi là bạn, tôi sẽ suy nghĩ lại về thiết kế các chức năng của mình. Tại sao g () chấp nhận tham chiếu, nó có sửa đổi tham số không? Nếu không, làm cho nó là tham chiếu, nếu có, tại sao bạn cố gắng chuyển tạm thời cho nó, bạn không quan tâm đó là tạm thời bạn đang sửa đổi? Tại sao getx () trở lại tạm thời? Nếu bạn chia sẻ với chúng tôi kịch bản thực sự của bạn và những gì bạn đang cố gắng thực hiện, bạn có thể nhận được một số đề xuất tốt về cách thực hiện.

Đi ngược lại với ngôn ngữ và đánh lừa trình biên dịch hiếm khi giải quyết vấn đề - thông thường nó tạo ra vấn đề.


Chỉnh sửa: Giải quyết các câu hỏi trong nhận xét: 1) X& x = getx().ref(); // OK when will x die?- Tôi không biết và tôi không quan tâm, bởi vì đây chính xác là những gì tôi muốn nói là "đi ngược lại ngôn ngữ". Ngôn ngữ nói "tạm thời chết ở cuối câu lệnh, trừ khi chúng bị ràng buộc với tham chiếu const, trong trường hợp chúng chết khi tham chiếu vượt quá phạm vi". Áp dụng quy tắc đó, có vẻ như x đã chết ở đầu câu lệnh tiếp theo, vì nó không bị ràng buộc với tham chiếu const (trình biên dịch không biết ref () trả về cái gì). Đây chỉ là một phỏng đoán.

2) Tôi đã nêu rõ mục đích: bạn không được phép sửa đổi tạm thời, vì nó chỉ không có ý nghĩa (bỏ qua các tham chiếu giá trị C ++ 0x). Câu hỏi "tại sao tôi được phép gọi các thành viên không phải là const?" là một câu hỏi hay, nhưng tôi không có câu trả lời tốt hơn câu tôi đã nêu ở trên.

3) Chà, nếu tôi đúng về x khi X& x = getx().ref();chết ở cuối bản tuyên bố, thì vấn đề là rõ ràng.

Dù sao, dựa trên câu hỏi và nhận xét của bạn, tôi không nghĩ ngay cả những câu trả lời bổ sung này cũng sẽ làm bạn hài lòng. Đây là một nỗ lực / tóm tắt cuối cùng: Ủy ban C ++ đã quyết định không sửa đổi thời gian, do đó, họ không cho phép ràng buộc với các tham chiếu không liên tục. Có thể một số triển khai trình biên dịch hoặc các vấn đề lịch sử cũng có liên quan, tôi không biết. Sau đó, một số trường hợp cụ thể đã xuất hiện và đã quyết định rằng chống lại tất cả các tỷ lệ cược, họ vẫn sẽ cho phép sửa đổi trực tiếp thông qua việc gọi phương thức không phải là const. Nhưng đó là một ngoại lệ - bạn thường không được phép sửa đổi tạm thời. Vâng, C ++ thường kỳ lạ.


2
@sbk: 1) Trên thực tế, cụm từ thích hợp là: "... ở cuối biểu thức đầy đủ ...". Một "biểu thức đầy đủ", tôi tin rằng, được định nghĩa là một biểu thức không phải là biểu thức con của một số biểu thức khác. Cho dù điều này luôn giống như "kết thúc của tuyên bố", tôi không chắc chắn.
sbi

5
@sbk: 2) Trên thực tế, bạn được phép sửa đổi giá trị (tạm thời). Nó bị cấm đối với các loại tích hợp ( intv.v.), nhưng nó được phép cho các loại do người dùng xác định : (std::string("A")+"B").append("C").
sbi

6
@sbk: 3) Lý do Stroustrup cho (trong D & E) cho không cho phép các ràng buộc của rvalues để tham khảo không const là, nếu Alexey của g()sẽ sửa đổi các đối tượng (mà bạn mong đợi từ một chức năng tham gia một tham chiếu không const), nó sẽ sửa đổi một đối tượng sắp chết, vì vậy dù sao cũng không ai có thể nhận được giá trị đã sửa đổi. Ông nói rằng điều này, rất có thể, là một lỗi.
sbi

2
@sbk: Tôi xin lỗi nếu tôi đã xúc phạm bạn, nhưng tôi không nghĩ 2) là nitpicking. Các giá trị đơn giản không phải là const trừ khi bạn thực hiện chúng và bạn có thể thay đổi chúng, trừ khi chúng được tích hợp sẵn. Phải mất một thời gian tôi mới hiểu được, ví dụ, ví dụ về chuỗi, tôi có làm gì sai không (JFTR: Tôi không), vì vậy tôi có xu hướng coi trọng sự khác biệt này.
sbi

5
Tôi đồng ý với sbi - vấn đề này hoàn toàn không phải là nitpicking. Đó là tất cả các cơ sở của ngữ nghĩa di chuyển rằng các giá trị loại lớp được giữ tốt nhất không phải là hằng.
Julian Schaub - litb

38

Trong mã của bạn getx()trả về một đối tượng tạm thời, cái gọi là "giá trị". Bạn có thể sao chép các giá trị vào các đối tượng (còn gọi là các biến) hoặc liên kết chúng với các tham chiếu const (sẽ kéo dài thời gian sống của chúng cho đến hết tuổi thọ của tham chiếu). Bạn không thể liên kết giá trị với các tham chiếu không const.

Đây là một quyết định thiết kế có chủ ý nhằm ngăn người dùng vô tình sửa đổi một đối tượng sẽ chết ở cuối biểu thức:

g(getx()); // g() would modify an object without anyone being able to observe

Nếu bạn muốn làm điều này, trước tiên bạn sẽ phải tạo một bản sao cục bộ hoặc của đối tượng hoặc liên kết nó với một tham chiếu const:

X x1 = getx();
const X& x2 = getx(); // extend lifetime of temporary to lifetime of const reference

g(x1); // fine
g(x2); // can't bind a const reference to a non-const reference

Lưu ý rằng tiêu chuẩn C ++ tiếp theo sẽ bao gồm các tham chiếu giá trị. Do đó, những gì bạn biết là tài liệu tham khảo đang trở thành được gọi là "tài liệu tham khảo lvalue". Bạn sẽ được phép liên kết các giá trị với các tham chiếu giá trị và bạn có thể quá tải các hàm trên "rvalue-ness":

void g(X&);   // #1, takes an ordinary (lvalue) reference
void g(X&&);  // #2, takes an rvalue reference

X x; 
g(x);      // calls #1
g(getx()); // calls #2
g(X());    // calls #2, too

Ý tưởng đằng sau các tham chiếu rvalue là, vì dù sao các đối tượng này sẽ chết, bạn có thể tận dụng kiến ​​thức đó và thực hiện cái gọi là "di chuyển ngữ nghĩa", một loại tối ưu hóa nhất định:

class X {
  X(X&& rhs)
    : pimpl( rhs.pimpl ) // steal rhs' data...
  {
    rhs.pimpl = NULL; // ...and leave it empty, but deconstructible
  }

  data* pimpl; // you would use a smart ptr, of course
};


X x(getx()); // x will steal the rvalue's data, leaving the temporary object empty

2
Xin chào, đây là một câu trả lời tuyệt vời. Cần phải biết một điều, g(getx())không làm việc vì chữ ký của nó là g(X& x)get(x)trả về một đối tượng tạm thời, vì vậy chúng tôi không thể ràng buộc một đối tượng tạm thời ( rvalue ) vào một tham chiếu không liên tục, có đúng không? Và trong đoạn mã đầu tiên của bạn, tôi nghĩ nó sẽ const X& x2 = getx();thay vì const X& x1 = getx();..
SexyBeast

1
Cảm ơn bạn đã chỉ ra lỗi này trong câu trả lời của tôi 5 năm sau khi tôi viết nó! :-/Đúng, lý luận của bạn là chính xác, mặc dù hơi ngược: Chúng ta không thể liên kết tạm thời với các consttham chiếu không (lvalue), và do đó, tạm thời được trả về bởi getx()(và không get(x)) không thể bị ràng buộc với tham chiếu lvalue mà đối số g().
sbi

Umm, ý của bạn là gì getx()(và không get(x)) ?
SexyBeast

Khi tôi viết "... getx () (và không nhận (x)) ..." , ý tôi là tên của hàm là getx()chứ không phải get(x)(như bạn đã viết).
sbi

Câu trả lời này trộn lẫn thuật ngữ. Một giá trị là một thể loại biểu thức. Một đối tượng tạm thời là một đối tượng. Một giá trị có thể hoặc không thể biểu thị một đối tượng tạm thời; và một đối tượng tạm thời có thể hoặc không thể được biểu thị bằng một giá trị.
MM

16

Những gì bạn đang thể hiện là chuỗi nhà điều hành được phép.

 X& x = getx().ref(); // OK

Biểu thức là 'getx (). Ref ();' và điều này được thực thi để hoàn thành trước khi gán cho 'x'.

Lưu ý rằng getx () không trả về một tham chiếu mà là một đối tượng được hình thành đầy đủ vào bối cảnh cục bộ. Đối tượng là tạm thời nhưng nó không phải là const, do đó cho phép bạn gọi các phương thức khác để tính toán một giá trị hoặc có các tác dụng phụ khác xảy ra.

// It would allow things like this.
getPipeline().procInstr(1).procInstr(2).procInstr(3);

// or more commonly
std::cout << getManiplator() << 5;

Nhìn vào phần cuối của câu trả lời này để biết ví dụ tốt hơn về điều này

Bạn không thể liên kết tạm thời với một tham chiếu vì làm như vậy sẽ tạo ra một tham chiếu đến một đối tượng sẽ bị hủy ở cuối biểu thức, do đó để lại cho bạn một tham chiếu lơ lửng (không gọn gàng và tiêu chuẩn không thích lộn xộn).

Giá trị được trả về bởi ref () là một tham chiếu hợp lệ nhưng phương thức không chú ý đến tuổi thọ của đối tượng mà nó đang trả về (vì nó không thể có thông tin đó trong ngữ cảnh của nó). Về cơ bản, bạn vừa thực hiện tương đương với:

x& = const_cast<x&>(getX());

Lý do có thể làm điều này với tham chiếu const cho một đối tượng tạm thời là vì tiêu chuẩn kéo dài tuổi thọ của thời gian tạm thời đến tuổi thọ của tài liệu tham khảo để tuổi thọ của các đối tượng tạm thời được kéo dài ra ngoài cuối tuyên bố.

Vì vậy, câu hỏi duy nhất còn lại là tại sao tiêu chuẩn không muốn cho phép tham chiếu đến các thời gian để kéo dài tuổi thọ của đối tượng ngoài phần cuối của câu lệnh?

Tôi tin rằng đó là bởi vì làm như vậy sẽ làm cho trình biên dịch rất khó để có được chính xác cho các đối tượng tạm thời. Nó được thực hiện cho các tham chiếu const đến tạm thời vì điều này có hạn sử dụng và do đó buộc bạn phải tạo một bản sao của đối tượng để làm bất cứ điều gì hữu ích nhưng cung cấp một số chức năng hạn chế.

Hãy nghĩ về tình huống này:

int getI() { return 5;}
int x& = getI();

x++; // Note x is an alias to a variable. What variable are you updating.

Kéo dài tuổi thọ của vật thể tạm thời này sẽ rất khó hiểu.
Trong khi sau đây:

int const& y = getI();

Sẽ cung cấp cho bạn mã mà nó là trực quan để sử dụng và hiểu.

Nếu bạn muốn sửa đổi giá trị, bạn nên trả lại giá trị cho một biến. Nếu bạn đang cố gắng tránh chi phí sao chép obejct trở lại từ hàm (vì có vẻ như đối tượng được sao chép được xây dựng lại (về mặt kỹ thuật là như vậy)). Vậy thì đừng bận tâm trình biên dịch rất giỏi trong 'Tối ưu hóa giá trị trả về'


3
"Vì vậy, câu hỏi duy nhất còn lại là tại sao tiêu chuẩn không muốn cho phép tham chiếu đến các thời gian để kéo dài tuổi thọ của đối tượng vượt quá cuối tuyên bố?" Thế là xong! Bạn hiểu câu hỏi của tôi. Nhưng tôi không đồng ý với ý kiến ​​của bạn. Bạn nói "làm cho trình biên dịch rất khó" nhưng nó đã được thực hiện để tham chiếu const. Bạn nói trong mẫu của bạn "Lưu ý x là bí danh của một biến. Bạn đang cập nhật biến nào." Không vấn đề gì. Có biến duy nhất (tạm thời). Một số đối tượng tạm thời (bằng 5) phải được thay đổi.
Alexey Malistov

@Martin: Tham khảo lủng lẳng không chỉ không gọn gàng. Chúng có thể dẫn đến các lỗi nghiêm trọng khi được truy cập sau này trong phương thức!
mmmmmmmm

1
@Alexey: Lưu ý rằng thực tế ràng buộc nó với tham chiếu const giúp tăng tuổi thọ tạm thời là một ngoại lệ được thêm vào một cách có chủ ý (TTBOMK để cho phép tối ưu hóa thủ công). Không có ngoại lệ được thêm vào cho các tham chiếu không phải là const, bởi vì ràng buộc tạm thời với một tham chiếu không const được xem là rất có thể là lỗi lập trình viên.
sbi

1
@alexy: Tham chiếu đến một biến bất khả xâm phạm! Không phải là trực giác.
Martin York

const_cast<x&>(getX());không có ý nghĩa
tò mò

10

Tại sao được thảo luận trong Câu hỏi thường gặp về C ++ (phần in đậm của tôi):

Trong C ++, các tham chiếu không phải const có thể liên kết với các giá trị và các tham chiếu const có thể liên kết với các giá trị hoặc giá trị, nhưng không có gì có thể liên kết với một giá trị không const. Đó là để bảo vệ mọi người khỏi thay đổi giá trị của thời gian bị phá hủy trước khi giá trị mới của họ có thể được sử dụng . Ví dụ:

void incr(int& a) { ++a; }
int i = 0;
incr(i);    // i becomes 1
incr(0);    // error: 0 is not an lvalue

Nếu mức tăng (0) đó được cho phép hoặc một số tạm thời mà không ai từng thấy sẽ tăng lên hoặc - tệ hơn nhiều - giá trị 0 sẽ trở thành 1. Cái sau nghe có vẻ ngớ ngẩn, nhưng thực sự có một lỗi như vậy trong các trình biên dịch Fortran đầu tiên đã thiết lập dành một vị trí bộ nhớ để giữ giá trị 0.


Sẽ rất buồn cười khi thấy khuôn mặt của lập trình viên bị cắn bởi "lỗi không" của Fortran! x * 0 cho x? Gì? Gì??
John D

Lập luận cuối cùng đó là đặc biệt yếu. Không có trình biên dịch nào đáng nói đến sẽ thực sự thay đổi giá trị từ 0 thành 1, hoặc thậm chí diễn giải incr(0);theo cách như vậy. Rõ ràng, nếu điều này được cho phép, nó sẽ được hiểu là tạo một số nguyên tạm thời và chuyển nó đếnincr()
user3204459

6

Vấn đề chính là

g(getx()); //error

là một lỗi logic: gđang sửa đổi kết quả của getx()nhưng bạn không có bất kỳ cơ hội nào để kiểm tra đối tượng đã sửa đổi. Nếu gkhông cần sửa đổi tham số của nó thì nó sẽ không yêu cầu tham chiếu giá trị, nó có thể lấy tham số theo giá trị hoặc bằng tham chiếu const.

const X& x = getx(); // OK

là hợp lệ vì đôi khi bạn cần sử dụng lại kết quả của một biểu thức và khá rõ ràng rằng bạn đang xử lý một đối tượng tạm thời.

Tuy nhiên không thể thực hiện

X& x = getx(); // error

hợp lệ mà không làm cho g(getx())hợp lệ, đó là những gì các nhà thiết kế ngôn ngữ đã cố gắng tránh ở nơi đầu tiên.

g(getx().ref()); //OK

là hợp lệ vì các phương thức chỉ biết về hằng số của this , chúng không biết nếu chúng được gọi trên một giá trị hoặc trên một giá trị.

Như mọi khi trong C ++, bạn có một cách giải quyết cho quy tắc này nhưng bạn phải báo hiệu cho trình biên dịch rằng bạn biết bạn đang làm gì bằng cách rõ ràng:

g(const_cast<x&>(getX()));

5

Có vẻ như câu hỏi ban đầu là tại sao điều này không được phép đã được trả lời rõ ràng: "bởi vì rất có thể đó là một lỗi".

FWIW, tôi nghĩ tôi sẽ chỉ ra cách thực hiện nó, mặc dù tôi không nghĩ đó là một kỹ thuật tốt.

Lý do đôi khi tôi muốn chuyển tạm thời sang một phương thức lấy tham chiếu không phải là cố ý vứt bỏ một giá trị được trả về bằng tham chiếu mà phương thức gọi không quan tâm. Một cái gì đó như thế này:

// Assuming: void Person::GetNameAndAddr(std::string &name, std::string &addr);
string name;
person.GetNameAndAddr(name, string()); // don't care about addr

Như đã giải thích trong các câu trả lời trước, điều đó không được biên dịch. Nhưng điều này biên dịch và hoạt động chính xác (với trình biên dịch của tôi):

person.GetNameAndAddr(name,
    const_cast<string &>(static_cast<const string &>(string())));

Điều này chỉ cho thấy rằng bạn có thể sử dụng đúc để nói dối với trình biên dịch. Rõ ràng, sẽ tốt hơn nhiều khi khai báo và chuyển một biến tự động không sử dụng:

string name;
string unused;
person.GetNameAndAddr(name, unused); // don't care about addr

Kỹ thuật này đưa một biến cục bộ không cần thiết vào phạm vi của phương thức. Nếu vì lý do nào đó bạn muốn ngăn không cho nó được sử dụng sau này trong phương thức, ví dụ, để tránh nhầm lẫn hoặc lỗi, bạn có thể ẩn nó trong một khối cục bộ:

string name;
{
    string unused;
    person.GetNameAndAddr(name, unused); // don't care about addr
}

- Chris


4

Tại sao bạn đã bao giờ muốn X& x = getx();? Chỉ cần sử dụng X x = getx();và dựa vào RVO.


3
Trở thành tôi muốn gọi g(getx())hơn làg(getx().ref())
Alexey Malistov

4
@Alexey, đó không phải là một lý do thực sự. Nếu bạn làm điều đó, thì bạn sẽ có một lỗi logic ở mọi nơi, bởi vì gsẽ sửa đổi một cái gì đó mà bạn không thể nhúng tay vào nữa.
Julian Schaub - litb

3
@ JohannesSchaub-litb có lẽ anh ấy không quan tâm.
tò mò

" Dựa vào RVO " ngoại trừ nó không được gọi là "RVO".
tò mò

2
@cquilguy: Đó là một thuật ngữ rất được chấp nhận cho nó. Hoàn toàn không có gì sai khi gọi nó là "RVO".
Cún con

4

Cách giải quyết khác liên quan đến từ khóa 'có thể thay đổi'. Thực sự là xấu xa là một bài tập cho người đọc. Hoặc xem tại đây: http://www.ddj.com/cpp/184403758


3

Câu hỏi tuyệt vời, và đây là nỗ lực của tôi với một câu trả lời ngắn gọn hơn (vì rất nhiều thông tin hữu ích nằm trong các bình luận và khó có thể đào sâu trong tiếng ồn.)

Bất kỳ tham chiếu nào bị ràng buộc trực tiếp vào tạm thời sẽ kéo dài tuổi thọ của nó [12.2.5]. Mặt khác, một tham chiếu được khởi tạo với một tham chiếu khác sẽ không (ngay cả khi nó cuối cùng là tạm thời). Điều đó có ý nghĩa (trình biên dịch không biết tham chiếu đó đề cập đến cái gì).

Nhưng toàn bộ ý tưởng này là vô cùng khó hiểu. Ví dụ, const X &x = X();sẽ làm cho tạm thời kéo dài miễn là xtham chiếu, nhưng const X &x = X().ref();sẽ KHÔNG (ai biết những gì ref()thực sự trở lại). Trong trường hợp sau, hàm hủy cho Xđược gọi ở cuối dòng này. (Điều này có thể quan sát được với một hàm hủy không tầm thường.)

Vì vậy, nó có vẻ khó hiểu và nguy hiểm (tại sao lại làm phức tạp các quy tắc về thời gian sống của đối tượng?), Nhưng có lẽ cần ít nhất là các tham chiếu const, vì vậy tiêu chuẩn đã đặt ra hành vi này cho chúng.

[Từ nhận xét của sbi ]: Lưu ý rằng việc ràng buộc nó với tham chiếu const giúp nâng cao tuổi thọ của tạm thời là một ngoại lệ được thêm vào một cách có chủ ý (TTBOMK để cho phép tối ưu hóa thủ công). Không có ngoại lệ được thêm vào cho các tham chiếu không phải là const, bởi vì ràng buộc tạm thời với một tham chiếu không const được xem là rất có thể là lỗi lập trình viên.

Tất cả các tạm thời vẫn tồn tại cho đến khi kết thúc biểu thức đầy đủ. Để sử dụng chúng, tuy nhiên, bạn cần một mẹo như bạn có ref(). Đó là hợp pháp. Dường như không có lý do chính đáng nào để hoop thêm nhảy qua, ngoại trừ để nhắc nhở lập trình viên rằng có điều gì đó bất thường đang xảy ra (cụ thể là một tham số tham chiếu có sửa đổi sẽ nhanh chóng bị mất).

[Một nhận xét sbi khác ] Lý do Stroustrup đưa ra (trong D & E) vì không cho phép ràng buộc các giá trị với các tham chiếu không phải là vì, nếu g () của Alexey sẽ sửa đổi đối tượng (mà bạn mong đợi từ một hàm lấy không phải là hằng tham chiếu), nó sẽ sửa đổi một đối tượng sắp chết, vì vậy không ai có thể nhận được ở giá trị đã sửa đổi. Ông nói rằng điều này, rất có thể, là một lỗi.


2

"Rõ ràng là đối tượng tạm thời không phải là hằng số trong mẫu ở trên, vì các lệnh gọi đến các hàm không hằng được cho phép. Ví dụ, ref () có thể sửa đổi đối tượng tạm thời."

Trong ví dụ của bạn, getX () không trả về const X để bạn có thể gọi ref () theo cách tương tự như bạn có thể gọi X (). Ref (). Bạn đang trả về một ref không phải const và vì vậy có thể gọi các phương thức non const, điều bạn không thể làm là gán ref cho tham chiếu non const.

Cùng với bình luận SadSidos, điều này làm cho ba điểm của bạn không chính xác.


1

Tôi có một kịch bản tôi muốn chia sẻ nơi tôi ước mình có thể làm những gì Alexey đang yêu cầu. Trong một plugin Maya C ++, tôi phải thực hiện các shenanigan sau để có được giá trị vào thuộc tính nút:

MFnDoubleArrayData myArrayData;
MObject myArrayObj = myArrayData.create(myArray);   
MPlug myPlug = myNode.findPlug(attributeName);
myPlug.setValue(myArrayObj);

Điều này thật tẻ nhạt để viết, vì vậy tôi đã viết các hàm trợ giúp sau:

MPlug operator | (MFnDependencyNode& node, MObject& attribute){
    MStatus status;
    MPlug returnValue = node.findPlug(attribute, &status);
    return returnValue;
}

void operator << (MPlug& plug, MDoubleArray& doubleArray){
    MStatus status;
    MFnDoubleArrayData doubleArrayData;
    MObject doubleArrayObject = doubleArrayData.create(doubleArray, &status);
    status = plug.setValue(doubleArrayObject);
}

Và bây giờ tôi có thể viết mã từ đầu bài như:

(myNode | attributeName) << myArray;

Vấn đề là nó không được biên dịch bên ngoài Visual C ++, vì nó đang cố gắng liên kết biến tạm thời được trả về từ | toán tử đến tham chiếu MPlug của toán tử <<. Tôi muốn nó là một tài liệu tham khảo vì mã này được gọi nhiều lần và tôi không muốn MPlug bị sao chép quá nhiều. Tôi chỉ cần đối tượng tạm thời để sống cho đến khi kết thúc chức năng thứ hai.

Vâng, đây là kịch bản của tôi. Chỉ cần nghĩ rằng tôi sẽ đưa ra một ví dụ mà người ta muốn làm những gì Alexey mô tả. Tôi hoan nghênh tất cả các phê bình và đề xuất!

Cảm ơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.