Почему я не могу использовать ссылочный тип как элемент std :: vector [duplicate]

Когда обещание будет разрешено / отклонено, оно вызовет его обработчик успеха / ошибки:

var promiseB = promiseA.then(function(result) {
   // do something with result
});

Метод then также возвращает обещание: promB, которое будет разрешено / отклонено в зависимости от возвращаемое значение из обработчика успеха / ошибки из обещания.

Есть три возможных значения, которые могут быть возвращены обработчикам успеха / ошибок, которые повлияют на результат результата:

1. Return nothing --> PromiseB is resolved immediately, 
   and undefined is passed to the success handler of promiseB
2. Return a value --> PromiseB is resolved immediately,
   and the value is passed to the success handler of promiseB
3. Return a promise --> When resolved, promiseB will be resolved. 
   When rejected, promiseB will be rejected. The value passed to
   the promiseB's then handler will be the result of the promise

Вооружено это понимание, вы можете понять следующее:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

Затем вызов немедленно возвращает обещаниеB. Когда обещание будет разрешено, оно передаст результат, чтобы обещать успешный обработчик. Поскольку возвращаемое значение является результатом promA + 1, обработчик успеха возвращает значение (вариант 2 выше), так что обещаниеB будет немедленно устранено, а обработчик успеха пообещания будет передан с обещанием результата + 1.

276
задан Violet Giraffe 14 June 2014 в 08:32
поделиться

8 ответов

Это недостаток языка C ++. Вы не можете взять адрес ссылки, так как попытка сделать это приведет к адресу адреса, на который ссылается, и, следовательно, вы никогда не сможете получить указатель на ссылку. std::vector работает с указателями на его элементы, поэтому для сохранения значений нужно указывать. Вместо этого вам придется использовать указатели.

11
ответ дан Adam Rosenfield 19 August 2018 в 12:42
поделиться
  • 1
    Я предполагаю, что это может быть реализовано с использованием буфера void * и нового места размещения. Не то, чтобы это имело смысл. – peterchen 28 May 2009 в 19:19
  • 2
    «Недостаток в языке» слишком силен. Это по дизайну. Я не думаю, что требуется, чтобы вектор работал с указателями на элементы. Однако требуется, чтобы элемент был назначен. Ссылки отсутствуют. – Brian Neal 28 May 2009 в 20:28
  • 3
    Вы не можете взять sizeof ссылку. – David Schwartz 17 May 2016 в 00:11
  • 4
    вам не нужен указатель на ссылку, у вас есть ссылка, если вам нужен указатель, просто держите указатель сам; здесь не проблема. – Ion Todirel 3 December 2017 в 02:53

По самой своей природе ссылки могут быть установлены только в момент их создания; т. е. следующие две строки имеют очень разные эффекты:

int & A = B;   // makes A an alias for B
A = C;         // assigns value of C to B.

Futher, это незаконно:

int & D;       // must be set to a int variable.

Однако, когда вы создаете вектор, присваивать значения своим элементам при создании. Вы, по сути, просто делаете целую кучу последнего примера.

26
ответ дан Diamond Python 19 August 2018 в 12:42
поделиться
  • 1
    & quot ;, когда вы создаете вектор, нет способа присвоить значения его элементам при создании & quot; Я не понимаю, что вы подразумеваете под этим заявлением. Что такое «его элементы при создании»? Я могу создать пустой вектор. И я могу добавлять элементы с .push_back (). Вы просто указываете, что ссылки не являются конструктивными по умолчанию. Но я могу определенно иметь векторы классов, которые не являются конструктивными по умолчанию. – newacct 28 May 2009 в 19:35
  • 2
    Элемент ype std :: vector & lt; T & gt; не обязательно должен быть конструктивным по умолчанию. Вы можете написать struct A {A (int); private: A (); }; вектор & л, A & GT; а; просто отлично - если вы не используете такие методы, которые требуют, чтобы он был по умолчанию конструктивным (например, v.resize (100); - вместо этого вам нужно будет делать v.resize (100, A (1));) – Johannes Schaub - litb 28 May 2009 в 19:53
  • 3
    И как бы вы написали такой push_back () в этом случае? Он по-прежнему будет использовать назначение, а не строительство. – James Curran 28 May 2009 в 19:53
  • 4
    Джеймс Керран, здесь нет строительства по умолчанию. push_back просто размещение-новости A в предварительно выделенный буфер. См. Здесь: stackoverflow.com/questions/672352/… . Обратите внимание, что утверждение my - это только тот вектор, который может обрабатывать нестандартные по умолчанию типы. Разумеется, я не утверждаю, что он мог бы обрабатывать T & amp; (это, конечно, не может). – Johannes Schaub - litb 28 May 2009 в 20:02

boost::ptr_vector<int> будет работать.

Edit: было предложено использовать std::vector< boost::ref<int> >, который не будет работать, потому что вы не можете по умолчанию построить boost::ref .

14
ответ дан Drew Dormann 19 August 2018 в 12:42
поделиться
  • 1
    Но у вас могут быть векторные или нестандартные по умолчанию типы, не так ли? Вы должны быть осторожны, чтобы не использовать значение по умолчанию ctor. вектора – Manuel 4 February 2010 в 13:05
  • 2
    @Manuel: Или resize. – Lightness Races in Orbit 31 July 2014 в 12:00
  • 3
    Будьте осторожны, контейнеры указателей Boost приобретают эксклюзивное владение первыми. Quote : «Когда вам нужна общая семантика, эта библиотека не то, что вам нужно. & quot; – Matthäus Brandl 6 March 2015 в 15:03

Ион Тодирель уже упомянул ответ ДА, используя std::reference_wrapper. Начиная с C ++ 11 у нас есть механизм для извлечения объекта из std::vector и удаления ссылки с помощью std::remove_reference. Ниже приведен пример, скомпилированный с использованием g++ и clang с опцией -std=c++11 и выполнен успешно.

#include <iostream>
#include <vector>
#include<functional>

class MyClass {
public:
    void func() {
        std::cout << "I am func \n";
    }

    MyClass(int y) : x(y) {}

    int getval()
    {
        return x;
    }

private: 
        int x;
};

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

    MyClass obj1(2);
    MyClass obj2(3);

    MyClass& obj_ref1 = std::ref(obj1);
    MyClass& obj_ref2 = obj2;

    vec.push_back(obj_ref1);
    vec.push_back(obj_ref2);

    for (auto obj3 : vec)
    {
        std::remove_reference<MyClass&>::type(obj3).func();      
        std::cout << std::remove_reference<MyClass&>::type(obj3).getval() << "\n";
    }             
}
19
ответ дан Grimeh 19 August 2018 в 12:42
поделиться
  • 1
    Я не вижу значения в std::remove_reference<> здесь. Точка std::remove_reference<> должна позволять вам писать «тип T», но без ссылки, если она одна ». Таким образом, std::remove_reference<MyClass&>::type - это то же самое, что и запись MyClass. – alastair 18 February 2016 в 18:36
  • 2
    В этом нет никакого значения - вы можете просто написать for (MyClass obj3 : vec) std::cout << obj3.getval() << "\n"; (или for (const MyClass& obj3: vec), если вы объявите getval() const, как и должны). – Toby Speight 24 May 2017 в 09:32

Тип компонента контейнеров, таких как векторы, должен быть присваиваемым . Ссылки не назначаются (вы можете их инициализировать только один раз, когда они объявлены, и вы не можете заставить их ссылаться на что-то еще позже). Другие не назначаемые типы также не допускаются как компоненты контейнеров, например. vector<const int> не разрешено.

266
ответ дан laike9m 19 August 2018 в 12:42
поделиться
  • 1
    Вы говорите, что у меня нет вектора векторов? (Я уверен, что я сделал это ...) – James Curran 28 May 2009 в 19:29
  • 2
    Да, std :: vector & lt; станд :: вектор & Lt; & INT GT; & GT; правильно, std :: vector можно присваивать. – Martin Cote 28 May 2009 в 19:31
  • 3
    Действительно, это «фактический». причина. Ошибка, заключающаяся в том, что T * невозможна для T, является U & amp; является лишь побочным эффектом нарушенного требования о том, что T должно быть назначаемым. Если бы вектор смог точно проверить параметр типа, тогда он, вероятно, сказал бы «нарушенное требование: T & amp; не назначаемый & quot; – Johannes Schaub - litb 28 May 2009 в 19:47
  • 4
    Проверка назначаемой концепции в boost.org/doc/libs/1_39_0/doc/html/Assignable.html все операции, кроме свопа, действительны для ссылок. – amit_grepclub 18 August 2009 в 17:01
  • 5
    Я думаю, что тип компонента также должен быть по умолчанию конструктивным, нет? И ссылки тоже не таковы. – cdhowie 1 May 2013 в 22:24

Как уже упоминалось, вы, вероятно, в конечном итоге используете вектор указателей.

Однако вы можете захотеть вместо этого использовать ptr_vector !

2
ответ дан Martin Cote 19 August 2018 в 12:42
поделиться
  • 1
    Этот ответ не работает, поскольку ptr_vector должен быть хранилищем. То есть он удалит указатели при удалении. Поэтому он не может использоваться для его цели. – Klemens Morgenstern 3 October 2014 в 13:12

Как показывают другие комментарии, вы ограничены использованием указателей. Но если это помогает, вот один из способов избежать прямого обращения с указателями.

Вы можете сделать что-то вроде следующего:

vector<int*> iarray;
int default_item = 0; // for handling out-of-range exception

int& get_item_as_ref(unsigned int idx) {
   // handling out-of-range exception
   if(idx >= iarray.size()) 
      return default_item;
   return reinterpret_cast<int&>(*iarray[idx]);
}
0
ответ дан Omid 19 August 2018 в 12:42
поделиться

да, вы можете найти std::reference_wrapper , который имитирует ссылку, но назначается, а также может быть «повторно установлен»

82
ответ дан user1438233 19 August 2018 в 12:42
поделиться
  • 1
    Есть ли способ обойти вызов get() первым при попытке доступа к методу экземпляра класса в этой оболочке? Например. reference_wrapper<MyClass> my_ref(...); my_ref.get().doStuff(); не очень напоминает. – timdiels 17 October 2014 в 16:40
  • 2
    Разве это не сглаживается к самому типу, возвращая ссылку? – WorldSEnder 13 November 2014 в 13:52
  • 3
    – underscore_d 30 September 2018 в 12:50
Другие вопросы по тегам:

Похожие вопросы: