C ++: Неопределенная ссылка в Map :: insert [duplicate]

Во-первых, вам нужно иметь четкое представление о scope и поведении ключевого слова this в контексте scope.

this & amp; scope:


there are two types of scope in javascript. They are :

   1) Global Scope

   2) Function Scope

вкратце, глобальная область относится к объекту window.Variables, объявленные в глобальной области, доступны из любого места. С другой стороны, область функций находится внутри функции .variable, объявленный внутри функции, не может быть доступен из внешнего мира в обычном режиме. this ключевое слово в глобальной области относится к объекту window. Внутренняя функция this также относится к объекту window.So this всегда будет ссылаться на окно до тех пор, пока мы найдем способ манипулировать this, чтобы указать контекст по собственному выбору.

--------------------------------------------------------------------------------
-                                                                              -
-   Global Scope                                                               -
-   ( globally "this" refers to window object)                                 -     
-                                                                              -
-         function outer_function(callback){                                   -
-                                                                              -
-               // outer function scope                                        -
-               // inside outer function"this" keyword refers to window object -                                                                              -
-              callback() // "this" inside callback also refers window object  -

-         }                                                                    -
-                                                                              -
-         function callback_function(){                                        -
-                                                                              -
-                //  function to be passed as callback                         -
-                                                                              -
-                // here "THIS" refers to window object also                   -
-                                                                              -
-         }                                                                    -
-                                                                              -
-         outer_function(callback_function)                                    -
-         // invoke with callback                                              -
--------------------------------------------------------------------------------

Различные способы управления this внутри функций обратного вызова:

Здесь У меня есть функция-конструктор, называемая Person. Он имеет свойство, называемое name, и четыре метода, называемые sayNameVersion1, sayNameVersion2, sayNameVersion3, sayNameVersion4. Все четыре из них имеют одну конкретную задачу. Заберите обратный вызов и вызовите его. Обратный вызов имеет конкретную задачу, которая заключается в регистрации свойства имени экземпляра функции конструктора Person.

function Person(name){

    this.name = name

    this.sayNameVersion1 = function(callback){
        callback.bind(this)()
    }
    this.sayNameVersion2 = function(callback){
        callback()
    }

    this.sayNameVersion3 = function(callback){
        callback.call(this)
    }

    this.sayNameVersion4 = function(callback){
        callback.apply(this)
    }

}

function niceCallback(){

    // function to be used as callback

    var parentObject = this

    console.log(parentObject)

}

Теперь давайте создадим экземпляр из конструктора person и вызывать разные версии sayNameVersionX (X относится к 1,2,3,4) методу с niceCallback, чтобы увидеть, как много способов управления this внутри обратного вызова ссылаться на person.

var p1 = new Person('zami') // create an instance of Person constructor

bind:

Что нужно сделать, это создать новую функцию с ключевым словом this, установленным на предоставленное значение.

sayNameVersion1 и sayNameVersion2 используют bind для управления this функции обратного вызова.

this.sayNameVersion1 = function(callback){
    callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
    callback()
}

сначала связывают this с обратным вызовом внутри самого метода. для второго обратного вызова передается связанный с ним объект.

p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method

p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback

вызов:

first argument в call используется как функция this внутри функции, которая вызывается с call, прикрепленной к ней.

sayNameVersion3 использует call для управления this ], чтобы ссылаться на созданный нами объект person, а не на объект окна.

this.sayNameVersion3 = function(callback){
    callback.call(this)
}

и он называется следующим:

p1.sayNameVersion3(niceCallback)

apply:

Как и в call, первый аргумент apply относится к объекту, который будет обозначен ключевым словом this.

sayNameVersion4 использует apply для манипулирования this для обращения к объекту человека

this.sayNameVersion4 = function(callback){
    callback.apply(this)
}

, и он называется следующим. Просто передается обратный вызов,

p1.sayNameVersion4(niceCallback)

181
задан codeling 18 December 2015 в 12:56
поделиться

7 ответов

Вы должны фактически определить статический член где-нибудь (после определения класса). Попробуйте следующее:

class Foo { /* ... */ };

const int Foo::MEMBER;

int main() { /* ... */ }

Это должно избавиться от неопределенной ссылки.

183
ответ дан Drew Hall 21 August 2018 в 03:13
поделиться
  • 1
    Хорошая точка, встроенная статическая константная инициализация const, создает скользящую константу целого, которую вы не можете взять по адресу, а вектор принимает ссылочный параметр. – Evan Teran 7 November 2008 в 19:08
  • 2
    Этот ответ касается только первой части вопроса. Вторая часть намного интереснее: почему добавление ника NOP делает работу без необходимости внешней декларации? – nobar 1 February 2011 в 01:48
  • 3
    Я просто потратил немало времени на выяснение того, что если определение класса находится в файле заголовка, то распределение статической переменной должно быть в файле реализации, а не в заголовке. – shanet 14 July 2012 в 04:06
  • 4
    @shanet: Очень хороший момент - я должен был упомянуть об этом в своем ответе! – Drew Hall 14 July 2012 в 04:10
  • 5
    Но если я объявляю его как const, разве мне не возможно изменить значение этой переменной? – Namratha 27 November 2012 в 06:57

Aaa.h

class Aaa {

protected:

    static Aaa *defaultAaa;

};

Aaa.cpp

// You must define an actual variable in your program for the static members of the classes

static Aaa *Aaa::defaultAaa;
9
ответ дан ollo 21 August 2018 в 03:13
поделиться

Не знаю, почему работает бросок, но Foo :: MEMBER не выделяется до тех пор, пока Foo не будет загружен, и поскольку вы никогда не загружаете его, он никогда не выделяется. Если у вас есть ссылка на Foo где-то, это, вероятно, сработает.

1
ответ дан Paul Tomblin 21 August 2018 в 03:13
поделиться
  • 1
    Я думаю, что вы отвечаете на свой вопрос: бросок работает, потому что он создает (временную) ссылку. – Jaap Versteegh 30 November 2011 в 17:43

Проблема возникает из-за интересного столкновения новых функций C ++ и того, что вы пытаетесь сделать. Во-первых, давайте посмотрим на подпись push_back:

void push_back(const T&)

Ожидается ссылка на объект типа T. В старой системе инициализации такой член существует. Например, следующий код компилируется просто отлично:

#include <vector>

class Foo {
public:
    static const int MEMBER;
};

const int Foo::MEMBER = 1; 

int main(){
    std::vector<int> v;
    v.push_back( Foo::MEMBER );       // undefined reference to `Foo::MEMBER'
    v.push_back( (int) Foo::MEMBER ); // OK  
    return 0;
}

Это потому, что есть фактический объект где-то, у которого есть это значение, хранящееся в нем. Если, однако, вы переключитесь на новый метод указания статических константных элементов, как вы уже выше, Foo::MEMBER больше не является объектом. Это константа, несколько схожа с:

#define MEMBER 1

Но без головных болей макроса препроцессора (и с безопасностью типа). Это означает, что вектор, ожидающий ссылки, не может получить его.

70
ответ дан phoenix 21 August 2018 в 03:13
поделиться
  • 1
    Это имеет смысл – Evan Teran 7 November 2008 в 19:06
  • 2
    спасибо, что помогли ..., которые могли бы претендовать на stackoverflow.com/questions/1995113/strangest-language-feature , если его еще нет ... – Andre Holzner 3 December 2010 в 14:45
  • 3
    Также стоит отметить, что MSVC принимает безличную версию без жалоб. – porges 27 June 2012 в 00:49
  • 4
    -1: Это просто неверно. Вы все еще должны определять статические члены, инициализированные inline, когда они odr-used где-то. То, что оптимизация компилятора может избавиться от ошибки компоновщика, не меняет этого. В этом случае преобразование lvalue-to-rvalue (благодаря слиянию (int)) происходит в блоке трансляции с идеальной видимостью константы, а Foo::MEMBER больше не odr-used . Это контрастирует с первым вызовом функции, где ссылка передается и оценивается в другом месте. – Lightness Races in Orbit 6 October 2014 в 23:12

Что касается второго вопроса: push_ref принимает ссылку как параметр, и вы не можете иметь ссылку на static const memeber класса / struct. После вызова static_cast создается временная переменная. И ссылка на этот объект может быть передана, все работает отлично.

Или, по крайней мере, мой коллега, который разрешил это, сказал.

0
ответ дан Quarra 21 August 2018 в 03:13
поделиться

Стандарт C ++ требует определения для вашего статического члена константы, если определение каким-то образом необходимо.

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

Когда вы явно используете константу, вы создаете временное, и это временное, которое связано с ссылкой (по специальным правилам в стандарте).

Это действительно интересный случай, и я на самом деле думаю, что стоит подняться вопрос, чтобы std был изменен на имеют одинаковое поведение для вашего постоянного члена!

Хотя, в каком-то странном виде это можно рассматривать как законное использование унарного оператора «+». В основном результат unary + является rvalue, поэтому применяются правила привязки rvalues ​​к ссылкам const, и мы не используем адрес нашего статического члена const:

v.push_back( +Foo::MEMBER );
57
ответ дан Richard Corden 21 August 2018 в 03:13
поделиться
  • 1
    +1. Да, конечно, странно, что для объекта x типа T выражение "(T) x" могут быть использованы для связывания константы ref, тогда как простой "x" не может. Мне нравится ваше наблюдение за «унарным +». Кто бы мог подумать, что бедный маленький «унарный +» на самом деле было полезно ... :) – j_random_hacker 29 May 2009 в 11:38
  • 2
    Думая об общем случае ... Есть ли какой-либо другой тип объекта в C ++, который обладает свойством, что он (1) может использоваться как lvalue только в том случае, если он определен, но (2) может быть преобразован в rvalue без определены? – j_random_hacker 29 May 2009 в 11:51
  • 3
    Хороший вопрос, и по крайней мере на данный момент я не могу придумать никаких других примеров. Вероятно, это возможно только потому, что комитет в основном просто повторно использовал существующий синтаксис. – Richard Corden 29 May 2009 в 13:47
  • 4
    @RichardCorden: как унарный + разрешил это? – Blood-HaZaRd 28 June 2018 в 15:10
  • 5
    @ Blood-HaZaRd: перед ссылками rvalue единственной перегрузкой push_back была const &. Использование члена напрямую приводило к тому, что член привязывался к ссылке, что требовало наличия адреса. Однако добавление + создает временное значение со значением члена. Ссылка затем привязывается к этому временному, а не требует, чтобы у члена был адрес. – Richard Corden 13 July 2018 в 10:48

С C ++ 11 приведенное выше возможно для базовых типов как

class Foo {
public:  
  static constexpr int MEMBER = 1;  
};

Часть constexpr создает статическое выражение в противоположность статическому variable - и это ведет себя так же, как чрезвычайно простое определение встроенного метода. Тем не менее подход оказался немного шатким с C-string constexprs внутри классов шаблонов.

0
ответ дан starturtle 21 August 2018 в 03:13
поделиться
Другие вопросы по тегам:

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