×

Loading...
Ad by
  • 最优利率和cashback可以申请特批,好信用好收入offer更好。请点链接扫码加微信咨询,Scotiabank -- Nick Zhang 6478812600。
Ad by
  • 最优利率和cashback可以申请特批,好信用好收入offer更好。请点链接扫码加微信咨询,Scotiabank -- Nick Zhang 6478812600。

那几行代码没有任何问题,C++标准允许将一个在栈上的常量型引用指向一个从函数调用返回的临时对象,此时这个临时对象的生命期将被延长到跟被指向的引用变量相同。

当一个函数返回结构或者对象时,调用所产生的临时对象所占用的内存位于调用者的栈上,这块临时内存的地址通过一个隐含参数传递给被调函数(类似调用成员函数时this指针的传递),过程类似下面的代码:
std::string f()
{
    return std::string("hello");
}
int main()
{
    std::string str_temp;
    f(&str_temp);
    const std::string& str = str_temp;
    ...
    return 0;
}
因为这个临时对象位于调用者的栈上,当从被调函数返回时,这块内存是仍然有效的,所以C++标准允许使用一个常量引用去使用这块内存。如果使用微软的VC++的话,const可以去掉,编译器会给出一个代码不符合标准的警告,但是可以正常运行,因为这块位于栈上的临时对象其实是可以被修改的。 这个题的意义在于大部分C++程序员都会给出错误答案,这到底是知识点还是盲点估计不同的人会给出不同的解释。
Report

Replies, comments and Discussions:

  • 工作学习 / 学科技术讨论 / 新的一年了,列一道俺们公司去年的面试题让.net程序员消遣一下,这道题很少有人做对,唯一一个做对的让他讲出道理还没讲对:不要上机运行,请写出此程序的运行结果
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                ClassA<string> x1 = new ClassA<string>("I am here");
                ClassA<int> x2 = new ClassA<int>(20);
                ClassA<DateTime> x3 = new ClassA<DateTime>(DateTime.Now);
    
                Console.WriteLine(x1.MyIndex);
                Console.WriteLine(x2.MyIndex);
                Console.WriteLine(x3.MyIndex);
            }
        }
    
        public class ClassA<T>
        {
            public T Item
            {
                get;
                set;
            }
    
            public int MyIndex
            {
                get;
                set;
            }
    
            public ClassA(T source)
            {
                Item = source;
                MyIndex = classIndex++;
            }
    
            static int classIndex = 0;
        }
    }
    • 难道不是
      0
      1
      2
      • 原来你达特耐特也这么好!
      • 答案不对啊,此题考查的是程序员对泛型基本概念的理解
        • 原来如此啊。不过如果是这样,这个 static index 用的很 ugly。
          • 就是10几行考查基本功的考试题,没必要考虑什么丑不丑吧
            • 我之所以提出来它丑,是因为丑的用法实际中不常见,所以作为考题不合适。这个 generics 的概念,你们那些考生很可能是知道的,所以你们没有考出你们要考的东西。
              • 之所以出这道题是来自于实践的教训,俺们Team曾经有个程序员在调试泛型程序的时候用了一个自增加的static变量,他想通过监视这个static变量的值来查找一个bug,但是发现无论生成多少个object,这个static变量永远是0,花费了几个小时也没搞明白
                如果他对泛型的基础有深入一些的了解,就会省下这几个小时的时间
                • “如果他对泛型的基础有深入一些的了解,就会省下这几个小时的时间”:这一点不敢苟同啊。bug 往往不是因为概念不清,而是因为盲点。你们考的也不是面试人的概念,而是他们的盲点。
                • 比较有意思,用静态变量有时也需要的,看来得改成这样
                  public class ClassA<T> : ClassABase
                  {
                  public T Item
                  {
                  get;
                  set;
                  }

                  public int MyIndex
                  {
                  get;
                  set;
                  }

                  public ClassA(T source)
                  {
                  Item = source;
                  MyIndex = classIndex++;
                  }

                  }

                  public class ClassABase
                  {
                  internal static int classIndex = 0;

                  }
                  • 必须地
    • 顶. 欢迎 post 更多题名
    • 000
      • cool, but why?
        • MyIndex = classIndex++; 是说 MyIndex = classIndex + 1; 没说 MyIndex = classIndex = classIndex + 1;
          • nono,不是这个原因
            • this is question is not asking the question about application logic.
              But rather, it is asking if the job candidate for the understanding of .net library beyond version 2.0
              If the positions level is entry to intermediate, this is not a good interview question because it requires deeper understanding of the language and .net framework that might not be related to day to day development.

              Java background developer like me will have the 0 1 2 answer right away.
              C++ background developer will have something else.

              Unless knowing this differences between language is part of the requirement of the job. I don't think this is a very good interview question.
          • 答案如楼上所说是000,原因如下:
            本文发表在 rolia.net 枫下论坛ClassA<T> 是一个泛型类,当它每次被实例化的的时候,例如:
            ClassA<string> x1 = new ClassA<string>("I am here");
            ClassA<int> x2 = new ClassA<int>(20);
            .net编译器在碰到这样的泛型代码的时候会在后台生成这样两个毫无关系的类,用伪代码表示一下:

            public class ClassA'[string]
            {
            public string Item
            {
            get;
            set;
            }

            public int MyIndex
            {
            get;
            set;
            }

            public ClassA(string source)
            {
            Item = source;
            MyIndex = classIndex++;
            }

            static int classIndex = 0;
            }

            and

            public class ClassA'[int]
            {
            public int Item
            {
            get;
            set;
            }

            public int MyIndex
            {
            get;
            set;
            }

            public ClassA(int source)
            {
            Item = source;
            MyIndex = classIndex++;
            }

            static int classIndex = 0;
            }

            然后用这样两个独立生成的类去实例化两个变量:x1,和 x2
            因为x1和x2是由两个完全不同的类实例化而来,所以它们的 static int classIndex 当然毫无关系,所以最后输出结果为000更多精彩文章及讨论,请光临枫下论坛 rolia.net
        • I guess, because the static is on different classes. The generic is just syntactic sugar. Did not open the answer of big cat so not sure if it`s the same as his/hers.
          • simply put. .net# has each generic Class as an independent class in the CLR.
            so, the static member belong to each separate class, which initiated to 0 each time the new instance of an new class is created.
            • 恩,不错,我把题稍微改一下,不要上机运行,告诉我运行结果是什么?
              static void Main(string[] args)
              {
              ClassA<string> x1 = new ClassA<string>("I am here");
              ClassA<string> x2 = new ClassA<string>("666");
              ClassA<string> x3 = new ClassA<string>("777");

              Console.WriteLine(x1.MyIndex);
              Console.WriteLine(x2.MyIndex);
              Console.WriteLine(x3.MyIndex);

              Console.ReadLine();
              }
              • this time it should be 012, am i right?
                • yeah, right, ClassA<T>里面的T如果已经被实例化一次,那么就会用以前的Class
                  • 顺便问一下大猫, 以后的趋势好象只懂C#会是死路一条,你乍看?
                    • 我的意思是说C#的编程越来越少。
                      • 这个不知道,但是看CSDN的语言排行C#一直高踞前5位吧,不可能越来越少
            • 那如果再来个 ClassA<int> x4 =new ClassA<int>(20); then x4.MyIndex= 1. now is x2.MyIndex, 0 or 1? simply put, do generic class of same type share the static member?
              • they are the same class, the static variable is static for the same class. don't confuse between instance and class.
                • that's what I thought, thanks for the confirmation.
          • 说得不错,其实.net里面的泛型,用大白话说就是,在实例化ClassA<T,X>的时候,只要T,X不同那就是完全不同的Class,这一点,根据俺的经验,很多.net程序员不明白。我们team里面很多关于泛型的错误和问题,归根结底是程序员没明白这一点
    • 呵呵,
    • .NET的 generics 走的是C++的路子,和Java的处理方法非常不同。但是,我同意兵哥的看法,这题出得偏了。换句话说,实践的教训你们也学错了。当时你们的程序员正确的做法是先给自己的调试程序写unit test,否则早晚会碰上新的盲点。
      • 盲点是不可避免的吧。过去有,现在有,将来也有。谁敢称没有盲点。
        • 是的。所以考查应聘者有没有某个盲点,没有意义。应该考查有没有好的工作习惯。
          • 面试都是这样的。一两个细节不说明问题,但是看10个类似的细节,如果答得不好,说明这个人工作中不注意学习,技术很粗,水平不行。
            • 如果真是细节,那就没有考的必要了。编程的人每一段时间基本上都跟一两个技术打交道,这方面的细节你怎么考他都不怕。其他方面的细节如果他要通过考试,都是临时准备的,不考也罢。
            • 这个泛型里的 static,是概念,不是细节。但是这个概念不重要,因为它 ugly,容易造成盲点。码哥说的好,好的习惯重要。不做 ugly 的事情,就是码工的一个好习惯。这些 ugly 的事情,即使你大牛懂了,普通人也会犯错误。即使是大牛,也有走神的时候。
    • 遇到过一个类似的C++的简单概念题:
      std::string f()
      {
          return std::string("hello");
      }
      int main()
      {
          const std::string& str = f();
          cout << str.c_str() << endl;
          return 0;
      }
      
      这几行代码有没有问题?
      • 你这题考的是完全不同的技术点,而且是C++特有的。问题在const std::string& str = f(); 因为f()返回的对象在语句结束后内存释放了,引用拿到的是无效的对象了。去掉引用符号就对了,复制一个对象。
        • 那几行代码没有任何问题,C++标准允许将一个在栈上的常量型引用指向一个从函数调用返回的临时对象,此时这个临时对象的生命期将被延长到跟被指向的引用变量相同。
          当一个函数返回结构或者对象时,调用所产生的临时对象所占用的内存位于调用者的栈上,这块临时内存的地址通过一个隐含参数传递给被调函数(类似调用成员函数时this指针的传递),过程类似下面的代码:
          std::string f()
          {
              return std::string("hello");
          }
          int main()
          {
              std::string str_temp;
              f(&str_temp);
              const std::string& str = str_temp;
              ...
              return 0;
          }
          
          因为这个临时对象位于调用者的栈上,当从被调函数返回时,这块内存是仍然有效的,所以C++标准允许使用一个常量引用去使用这块内存。如果使用微软的VC++的话,const可以去掉,编译器会给出一个代码不符合标准的警告,但是可以正常运行,因为这块位于栈上的临时对象其实是可以被修改的。 这个题的意义在于大部分C++程序员都会给出错误答案,这到底是知识点还是盲点估计不同的人会给出不同的解释。
      • Is it that the 'str' references to a temporary string object ?
        • The code has nothing wrong, it's ok to use a (stack based) const reference on a temp object returned by a function call, the lifetime of the temp object will be extended to the lifetime of the reference.
          • Thanks. I'm not sure how each compiler handles the temporary object, it is like a grey zone in my point of view, so I never let a function return an object in this way.
    • 有意思。不过如果你使用 resharper,r# 会在 classIndex 上显示一个蓝线 warning: Static field in generic type。google 一下就会知道了。
    • 这种面试题一点意义都没有。
    • 哈哈,还从未被这样刁难。否则必死无疑。
    • i was thinking about 111. don't remember the order of = and ++
    • 多谢楼上一众回复,这题面试那么多人,没一个人真正做对,事后俺也想过是否太刁钻?不过俺只不过是想考察对方是否明白ClassA<string>和ClassA<int>是两个完全无关的Class,那么该如何修改此题,使其显得优美不刁钻,又能达到我的目的?请教了,呵呵
      • You guys are not nice. It took you guys hours to figure out what the heck's going on, but you want a job applicant to answer it in maybe an hour. Not fair, haha....
        不过你们也够可以的哈,一个十分钟二十分钟的事情需要半天哈。。。
      • 太细节了。看你的贴前我不会这道题。不过你自己的解释(1036 bytes. #8537697@0)也不完全对。
        ".net编译器在碰到这样的泛型代码的时候会在后台生成这样两个毫无关系的类,"

        这个不是编译器的事,是在runtime产生的,不同于一般的reference type,泛型是用metadata管理的。
      • 我觉得这种题还是不考的好,连老洪这样的大拿都不知道,因为没有这样用过,没有想过。软件有 state,就很 ugly。用 static state,是 double ugly。在 generic class 里用 static state,是 triple ugly。
        你们经常因为这个出 bug,是不是因为你们经常用 static state?

        从辩证的意义上讲,如果我招人,我宁愿招不懂这个概念的人,因为他不懂,说明他没有这样用过,也没有这样想过,说明他头脑简单。头脑简单的码工才能成为好码工。
        • +
        • 感叹一句,您深得道家政治理论的真传啊!
          • 同样感慨一句,这些回帖都是指点江山,高屋建瓴,气势磅礴,唯一的缺点就是 -- 没有半点解决俺的实际问题的意思。那么看来,这套题的写法只能是目前最好了?
            • 俺的一点儿愚见:给出结果问原因。 俺花5分钟Google了一下,找到满意答案
              • 给出结果就应该知道原因了。
                • 这题目不难,懂点儿基本概念后再Google一下,也就10分钟的事儿。
            • 这种题目答出来可以加分,答不出来不能说明对方不行。俺用 c++很多年了。你一说012不对,就知道答案了。但一开始也没想到。
            • 难道你就不会面试通过语言交流? 出考题的公司多半是面试官有交流障碍或是偏执狂, 这样的考试对初级职位尚可(因为对方无太多经历东西可谈), 对高级职位简直是侮辱被面试人。为啥你还乐此不彼?
            • 其实不知道这个概念也一样干活。实在要出题建议:Console.WriteLine(typeof(List<int>) == typeof(List<String>));
              • +1
      • 我理解为什么你们会碰上这个 bug,很多 framework 里面这么用 static(有不得已的原因,不展开了,真正 coder 能理解),所以如果 teammate 不了解这个就会产生 bug。但是用这个作为面试题,不见得合适,因为
        我觉得如果一个 coder 本来不知道,但碰到了这个问题,能很快地找到原因并第一时间理解这个原理,并且迅速排查系统中类似的出错点,就可以了。
        因为这样的概念点数不胜数,多背一两个,少背一两个不重要。重要的是第一时间 know why.

        顺便说一句,我问了我 team 里面一个年轻人(not even sr. dev),他随口给出了正确答案,因为他很喜欢 c++,经常比较 c++ 和 c# 的实现方式。另外他立刻提及了我们使用的中间件 framework 中和这个相关的 issue。
        • 误会了,static和bug没有关系,我们有时候在项目里面临时创建一个static变量,纯粹是为了找到bug,这是调试程序的一个基本方法,找出原因就undo everything
      • 我也认为面试这种题没有太大意义。实际中见过真正需要用这种static的,是COM class中需要保留一个counter来记着class被实例多少次。 其他的最好是stateless, 写这种code不但confuse自己几个小时, 以后别人接过来可能又造成confusion, 如果用了一定要明确的注释一下。
    • 楼上回帖的有个很大的误会,以为我们在项目中会随意使用static变量,实际上很少。用static变量纯粹是在调试程序找bug的时候临时用到,这牵扯到另外一个话题,在突然接触一个陌生项目让你修理一个defect你该怎样做?时间很紧,哪里有空让你创建什么unit test
      • 说你的公司奇怪,还真是奇怪。这道考题仅仅考了一个应用很窄的知识点。这样的问题,碰巧看过书碰巧记得的就答的出来,资深的程序员反而会犯错。而且你说时间紧,没有时间写Unit Test,说明你的公司对程序质量很不重视。时间紧绝不是不写test的借口。
        • 我觉得unit test不是很实用,效率低,加了代码就不是同一环境,错是在测试代码还是被测试代码里?几年前Visual Studio没有unit test的功能也好好的。
        • 不敢肯定资深人士会犯这个错 这错误只能说明不理解template机制 平时用只是照猫画虎
    • Template and static, old c++concept
    • 根据本人面试经历,很多技术面试主管有一种差不多的举动和心理:总拿自己不太懂的问题或自己曾搞错的问题去考问被面试者。这个题目相信也是差不多的来历。我说这个是对事不对人,楼主包涵。
      • 有点那种抠出点鼻屎,然后拿着,考问他人的感觉。这类问题答对答错,都和人的工作能力无关。纯属碰巧知道这么点没用的细节而已。
    • 程序实现还是越简单越好,关键是性能和稳定性。
    • 这是今天的面试题,有闲心的可以做做
      有一个数组,2维的,初始化如下:
      int[,] m = new int[50000, 50000];
      m[330,330] = 20;
      m[30, 30] = 20;
      int result = 0;

      问下面这两种循环执行速度怎样,是一样快,还是有区别,为啥?
      1)
      for (int x = 0; x < 50000; x++)
      for (int y = 0; y < 50000; y++)
      if (m[x, y] > 0)
      result++;

      2)
      for (int x = 0; x < 50000; x++)
      for (int y = 0; y < 50000; y++)
      if (m[y, x] > 0)
      result++;


      大家周末愉快
      • 通常1会快一些吧。因为循环的时候数据在同一个block里,系统的缓存和编译器生成的代码都会更有效率。
        • 假设是纯C,而且出题者想明白自己要问啥的话,2,因为C的里面的下标还是内存地址映射,这nestloop 的 y 更接近当前的TLB