2011年3月23日

The Filterator from Ahmed Charles

     摘要: My name is Ahmed Charles and I currently work on Windows Error Reporting. I believe that this is the first time that someone not on the VC team has written a blog, but I hope you will find it useful a...  阅读全文

posted @ 2011-03-23 17:12 Enki 阅读(395) | 评论 (0)编辑 收藏

Lambdas, auto, and static_assert: C++0x Features in VC10 from Stephan T. Lavavej

     摘要: The Visual C++ compiler in the Microsoft Visual Studio 2010 September Community Technology Preview (CTP) contains support for four C++0x language features, namely lambdas, auto, static_assert, and rva...  阅读全文

posted @ 2011-03-23 17:10 Enki 阅读(524) | 评论 (0)编辑 收藏

2011年3月22日

Expressive C++: Why Template Errors Suck and What You Can Do About It

     摘要: This entry is part of a series, Expressive C++» Entries in this series: Expressive C++: Introduction Expressive C++: Playing with Syntax Expressive C++: Why Template Errors Suck ...  阅读全文

posted @ 2011-03-22 18:17 Enki 阅读(976) | 评论 (0)编辑 收藏

Nested lambda's and 'this' pointers

C:\Temp>type meow.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

class Foo {

public:

    explicit Foo(const int x) : m_x(x) { }

 

    void mult(vector<vector<int>>& outer) const {

        for_each(outer.begin(), outer.end(), [&](vector<int>& inner) {

            for_each(inner.begin(), inner.end(), [&](int& elem) {

                elem *= m_x;

            });

        });

    }

 

private:

    int m_x;

};

 

int main() {

    Foo f(1000);

 

    vector<vector<int>> v(3, vector<int>(4));

 

    for (int i = 0; i < 3; ++i) {

        for (int j = 0; j < 4; ++j) {

            v[i][j] = i * 10 + j;

        }

    }

 

    f.mult(v);

 

    for (int i = 0; i < 3; ++i) {

        for (int j = 0; j < 4; ++j) {

            cout << v[i][j] << " ";

        }

 

        cout << endl;

    }

}

 

C:\Temp>cl

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 17.00.40309 for 80x86

Copyright (C) Microsoft Corporation.  All rights reserved.

 

usage: cl [ option... ] filename... [ /link linkoption... ]

 

C:\Temp>cl /EHsc /nologo /W4 meow.cpp

meow.cpp

meow.cpp(14) : error C3494: 'this' cannot be captured in a nested lambda

meow.cpp(14) : error C2065: 'm_x' : undeclared identifier

meow.cpp(14) : error C2065: 'm_x' : undeclared identifier

 

C:\Temp>g++ -Wall -Wextra -std=c++0x meow.cpp -o meow.exe

 

C:\Temp>meow

0 1000 2000 3000

10000 11000 12000 13000

20000 21000 22000 23000

 

There's a workaround:

 

C:\Temp>type meow.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

class Foo {

public:

    explicit Foo(const int x) : m_x(x) { }

 

    void mult(vector<vector<int>>& outer) const {

        const Foo * const myself = this;

 

        for_each(outer.begin(), outer.end(), [&](vector<int>& inner) {

            for_each(inner.begin(), inner.end(), [&](int& elem) {

                elem *= myself->m_x;

            });

        });

    }

 

private:

    int m_x;

};

 

int main() {

    Foo f(1000);

 

    vector<vector<int>> v(3, vector<int>(4));

 

    for (int i = 0; i < 3; ++i) {

        for (int j = 0; j < 4; ++j) {

            v[i][j] = i * 10 + j;

        }

    }

 

    f.mult(v);

 

    for (int i = 0; i < 3; ++i) {

        for (int j = 0; j < 4; ++j) {

            cout << v[i][j] << " ";

        }

 

        cout << endl;

    }

}

 

C:\Temp>cl /EHsc /nologo /W4 meow.cpp

meow.cpp

 

C:\Temp>meow

0 1000 2000 3000

10000 11000 12000 13000

20000 21000 22000 23000

 

C:\Temp>g++ -Wall -Wextra -std=c++0x meow.cpp -o meow.exe

 

C:\Temp>meow

0 1000 2000 3000

10000 11000 12000 13000

20000 21000 22000 23000

posted @ 2011-03-22 18:06 Enki 阅读(366) | 评论 (0)编辑 收藏

unexpected value from is_base_of

C:\Temp>type meow.cpp

#include <type_traits>

 

template <typename T> struct A {

    A() {

        static_assert(std::is_base_of<A<T>, T>::value, "assert1");

        typedef typename std::remove_reference<decltype(*this)>::type meow_t;

        static_assert(std::is_base_of<meow_t, T>::value, "assert2");

    }

};

 

struct C : public A<C> { };

 

void foo() {

    C c;

}

 

C:\Temp>cl

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 17.00.40316 for 80x86

Copyright (C) Microsoft Corporation.  All rights reserved.

 

usage: cl [ option... ] filename... [ /link linkoption... ]

 

C:\Temp>cl /EHsc /nologo /W4 /c meow.cpp

meow.cpp

 

C:\Temp>

 

*this is an lvalue so decltype(*this) is indeed A<T>&.

posted @ 2011-03-22 17:57 Enki 阅读(270) | 评论 (0)编辑 收藏

对volatile认识

 

from MSDN:

The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something other than statements, such as the operating system, the hardware, or a concurrently executing thread.

The following example declares a volatile integer nVint whose value can be modified by external processes:

int volatile nVint;

Objects declared as volatile are not used in optimizations because their value can change at any time. The system always reads the current value of a volatile object at the point it is requested, even if the previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.

One use of the volatile qualifier is to provide access to memory locations used by asynchronous processes such as interrupt handlers.

This means a value that can automatically change at any given instance. This is usually in reference to a hardware register that often has a different value ever time you read it. Specifically, it is useful to define some values as volatile so that a C compiler will not cache that value, but rather, get a fresh copy every time you request it's value. Otherwise, the compiler may return values which are inaccurate because it doesn't realized the value can change.

 

C:\tmp>type honor_volatile.c

#if !defined(VOLATILE)

#error

#endif

void test_one()

{

VOLATILE int x = 5;

}

void test_two(VOLATILE int x)

{

   x = 5;

}

 

C:\tmp>cl -O2 -c -Fa -DVOLATILE= honor_volatile.c

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 17.00.40308 for 80x86

Copyright (C) Microsoft Corporation.  All rights reserved.

 

honor_volatile.c

 

C:\tmp>type honor_volatile.asm

; Listing generated by Microsoft (R) Optimizing Compiler Version 17.00.40308.0

 

        TITLE   C:\tmp\honor_volatile.c

        .686P

        .XMM

        include listing.inc

        .model  flat

 

INCLUDELIB LIBCMT

INCLUDELIB OLDNAMES

 

PUBLIC  _test_one

PUBLIC  _test_two

; Function compile flags: /Ogtpy

;       COMDAT _test_two

_TEXT   SEGMENT

_x$ = 8                                                 ; size = 4

_test_two PROC                                          ; COMDAT

; File c:\tmp\honor_volatile.c

; Line 15

        ret     0

_test_two ENDP

_TEXT   ENDS

; Function compile flags: /Ogtpy

;       COMDAT _test_one

_TEXT   SEGMENT

_test_one PROC                                          ; COMDAT

; File c:\tmp\honor_volatile.c

; Line 10

        ret     0

_test_one ENDP

_TEXT   ENDS

END

 

C:\tmp>cl -O2 -c -Fa -DVOLATILE=volatile honor_volatile.c

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 17.00.40308 for 80x86

Copyright (C) Microsoft Corporation.  All rights reserved.

 

honor_volatile.c

 

C:\tmp>type honor_volatile.asm

; Listing generated by Microsoft (R) Optimizing Compiler Version 17.00.40308.0

 

        TITLE   C:\tmp\honor_volatile.c

        .686P

        .XMM

        include listing.inc

        .model  flat

 

INCLUDELIB LIBCMT

INCLUDELIB OLDNAMES

 

PUBLIC  _test_one

PUBLIC  _test_two

; Function compile flags: /Ogtpy

;       COMDAT _test_two

_TEXT   SEGMENT

_x$ = 8                                                 ; size = 4

_test_two PROC                                          ; COMDAT

; File c:\tmp\honor_volatile.c

; Line 14

        mov     DWORD PTR _x$[esp-4], 5

; Line 15

        ret     0

_test_two ENDP

_TEXT   ENDS

; Function compile flags: /Ogtpy

;       COMDAT _test_one

_TEXT   SEGMENT

_x$ = -4                                                ; size = 4

_test_one PROC                                          ; COMDAT

; File c:\tmp\honor_volatile.c

; Line 8

        push    ecx

; Line 9

        mov     DWORD PTR _x$[esp+4], 5

; Line 10

        pop     ecx

        ret     0

_test_one ENDP

_TEXT   ENDS

END

 

And this is assembly code from VS:

#include <stdio.h>
void main()
{
 volatile int i=10;
 int a = i;

 printf("i= %d\n",a);
 __asm {
  mov         dword ptr [ebp-4], 20h
 }

 int b = i;
 printf("i= %d\n",b);
}

 

Release:

009C1002  in          al,dx 

009C1003  push        ecx 

009C1004  push        esi 

 volatile int i=10;

int a = i;

 

printf("i= %d\n",a);

009C1005  mov         esi,dword ptr [__imp__printf (9C20A0h)] 

009C100B  mov         dword ptr [i],0Ah 

009C1012  mov         eax,dword ptr [i] 

009C1015  push        eax 

009C1016  push        offset string "i= %d\n" (9C20F4h) 

009C101B  call        esi 

009C101D  add         esp,8 

 __asm {

  mov         dword ptr [ebp-4], 20h

009C1020  mov         dword ptr [i],20h 

 }

 

int b = i;

009C1027  mov         eax,dword ptr [i] 

 printf("i= %d\n",b);

009C102A  push        eax 

009C102B  push        offset string "i= %d\n" (9C20F4h) 

009C1030  call        esi 

009C1032  add         esp,8 

009C1035  pop         esi 

}

009C1036  mov         esp,ebp 

009C1038  pop         ebp 

009C1039  ret 

 

 

Debug:

#include <stdio.h>

void main()

{

001B13B0  push        ebp 

001B13B1  mov         ebp,esp 

001B13B3  sub         esp,0E4h 

001B13B9  push        ebx 

001B13BA  push        esi 

001B13BB  push        edi 

001B13BC  lea         edi,[ebp-0E4h] 

001B13C2  mov         ecx,39h 

001B13C7  mov         eax,0CCCCCCCCh 

001B13CC  rep stos    dword ptr es:[edi] 

 volatile int i=10;

001B13CE  mov         dword ptr [i],0Ah 

 int a = i;

001B13D5  mov         eax,dword ptr [i] 

001B13D8  mov         dword ptr [a],eax 

 

printf("i= %d\n",a);

001B13DB  mov         esi,esp 

001B13DD  mov         eax,dword ptr [a] 

001B13E0  push        eax 

001B13E1  push        offset string "i= %d\n" (1B573Ch) 

001B13E6  call        dword ptr [__imp__printf (1B82D4h)] 

001B13EC  add         esp,8 

001B13EF  cmp         esi,esp 

001B13F1  call        @ILT+300(__RTC_CheckEsp) (1B1131h) 

 __asm {

  mov         dword ptr [ebp-4], 20h

001B13F6  mov         dword ptr [ebp-4],20h 

 }

 

int b = i;

001B13FD  mov         eax,dword ptr [i] 

001B1400  mov         dword ptr [b],eax 

 printf("i= %d\n",b);

001B1403  mov         esi,esp 

001B1405  mov         eax,dword ptr [b] 

001B1408  push        eax 

001B1409  push        offset string "i= %d\n" (1B573Ch) 

001B140E  call        dword ptr [__imp__printf (1B82D4h)] 

001B1414  add         esp,8 

001B1417  cmp         esi,esp 

001B1419  call        @ILT+300(__RTC_CheckEsp) (1B1131h) 

}

 

C:\Temp>type meow.cpp

#include <stdio.h>

 

int main() {

    MEOW int i = 10;

    int a = i;

 

    printf("a: %d\n", a);

 

    __asm {

        mov dword ptr [ebp - 4], 20h

    }

 

    int b = i;

 

    printf("b: %d\n", b);

}

 

C:\Temp>cl /EHsc /nologo /W4 /MTd /DMEOW= meow.cpp && meow

meow.cpp

a: 10

b: 32

 

C:\Temp>cl /EHsc /nologo /W4 /MT /O2 /DMEOW= meow.cpp && meow

meow.cpp

a: 10

b: 10

 

C:\Temp>cl /EHsc /nologo /W4 /MTd /DMEOW=volatile meow.cpp && meow

meow.cpp

a: 10

b: 32

 

C:\Temp>cl /EHsc /nologo /W4 /MT /O2 /DMEOW=volatile meow.cpp && meow

meow.cpp

a: 10

b: 32

 

Volatility inhibits optimizations, as expected.

posted @ 2011-03-22 17:55 Enki 阅读(432) | 评论 (0)编辑 收藏

2011年3月18日

对const的一些认识

以const 修饰的常量值,具有不可变性。
C++的编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量。


const 用于指针的两种情况分析:

int const *a; //a/可变,*a不可变

int *const a; //a不可变,*a可变

比如:

typedef char* pStr;

char string[4] = "abc";

//限定*p1不可变,当然p1可变。

const char* p1 = string;

const pStr p2 = string;

p1++; //可行 输出bc

p2++; //不可行

const int nValue; //nValue 是const
const char* pContent; //*pContent是const, pContent可变
char* const pContent;  //pContent是const, *pContent可变
const char* const pContent; //pContent和*pContent都是const























#include <iostream>
#include <string>

using namespace std;
string test[] ={"test"};

class StringStack
{
static const int size =100;
const string* stack[size];
int index;
public:
StringStack();
         //限定参数在函数体中不可被改变
void push(const string* s);
const string* pop();
         //尝试去更改
         const string* change(string* s,const string* ss);


};
const string* StringStack::change(string* s,const string* ss)
{
ss=s;
return ss;
}
StringStack::StringStack():index(0)
{
memset(stack,0,size * sizeof(string*));
}

void StringStack::push(const string* s)
{
if(index<size)
{
                   //改变传进来的常量
                   s=change(test,s);
                   //在汇编中可以看出:
0x0137E1C0  68 52 1d 00 63 72 65 61 6d 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 0f 00 00 00 00 00 00 00 b0 52 1d 00 72 69 70 70  hR..cream.......................?R..ripp
0x0137E1E8  6c 65 00 00 00 00 00 00 00 00 00 00 06 00 00 00 0f 00 00 00 00 00 00 00 f8 52 1d 00 6c 65 6d 6f 6e 00 00 00 00 00 00 00  le......................?R..lemon.......
0x0137E210  00 00 00 00 05 00 00 00 0f 00 00 00 00 00 00 00 40 53 1d 00 73 6f 72 62 65 74 00 00 00 00 00 00 00 00 00 00 06 00 00 00  ................@S..sorbet..............
0x0137E238  0f 00 00 00 00 00 00 00 88 53 1d 00 72 6f 63 6b 79 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 0f 00 00 00 00 00 00 00  ........?S..rocky.......................
0x0137E260  d0 53 1d 00 66 75 64 67 65 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00  ?S..fudge...............................
0x0137E288  01 00 00 00 d8 22 1d 00 88 51 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ....?"..?Q..............................
0x0137E2B0  00 00 00 00 00 00 00 00 00 4c cc 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  .........L?.............................
stack[index++]=s;
}
}
//限定函数的返回值不可被更新。
const string* StringStack::pop()
{

if(index>0)
{
const string* rv =stack[--index];
stack[index]=0;
return rv;
}
return 0;
}


string iceCream[]=
{
"cream","ripple","lemon","sorbet","rocky","fudge",
};

const int iCsz=sizeof iceCream / sizeof *iceCream;

int main()
{
StringStack ss;
for(int i=0;i<iCsz;i++)
{
ss.push(&iceCream[i]);
}
const string* cp;
while((cp=ss.pop())!=0)
 // ss已经指向了test;所以输出的都是test;

cout<<*cp<<endl;
}

posted @ 2011-03-18 16:32 Enki 阅读(312) | 评论 (0)编辑 收藏

2011年3月3日

C++/CLI to C++ Tips and Tricks

orignal reference: http://blogs.msdn.com/b/jsocha/archive/2011/03/02/c-cli-to-c-tips-and-tricks.aspx

In my previous post, Writing Unit Tests in Visual Studio for Native C++, I described the approach I’m using to write unit tests for native C++ code by using C++/CLI, which is C++ code that runs inside the .NET runtime. Because of this “mixed” programming model, there are some techniques you may need to employ between C++ and C++/CLI code.

Class Instance Variables

The instance variables in C++/CLI classes are different from instance variables in naïve C++, which means you can’t mix the two blindly. For example, you can’t use native C++ classes as instance variables in your test class. The following, for example, will not compile:

public ref class MyFixture
{
MyClass m_instance;
};
You’ll get the following error message:

error C4368: cannot define 'm_instance' as a member of managed 'Tests::MyFixture': mixed types are not supported

So how do you deal with this? Instead of using a class as the type, you have to use pointers and then create/destroy the instance in the TestInitialize and TestCleanup code:

public ref class MyFixture
{
[TestInitialize]
void Initialize()
{
m_pInstance = new MyClass();
}



[TestCleanup]
void Cleanup()
{
delete m_pInstance;
}



MyClass *m_pInstance;
};


The methods marked by TestInitialize and TestCleanup run before and after each test method.

Passing a Pointer to an Instance Variable

C++/CLI instance variables have a type of interior_ptr<T> instead of the type you wrote in your code. This makes a difference if you attempt to pass either the address or a reference to this instance variable to a native C++ method or function. For example, given the class above, you might think you could write a call to one of your native methods like this:

p->SomeMethod(&m_pInstance);

Compile this and you’ll see this message:

error C2664: 'Tests::MyFixture::MyTest' : cannot convert parameter 2 from 'cli::interior_ptr<Type>' to 'MyClass **'

This error appears because .NET uses a heap—items on the heap can be moved as a result of garbage collection. In order to send a pointer to a native method/function, you need to “pin” the pointer for the duration of the call, which you can do like this:

cli::pin_ptr<MyClass *> p = &m_pInstance;
SomeMethod(static_cast<MyClass **>(p));

Once the variable p either goes out of scope, or is assigned a new value, the pointer will be free to change again.

When you’re dealing with helper methods in your test code, you can also write this type of code:

Helper(&m_pInstance);
...
void Helper(cli::interior_ptr<MyClass *> ppInstance)
{
**ppInstance =
new
MyClass();
}

posted @ 2011-03-03 11:19 Enki 阅读(635) | 评论 (0)编辑 收藏

2011年3月2日

Are lambdas preferable to bind nowadays? Which would you write?

 

function<void()> task = bind( &File::HashFile, static_cast<HashFn>(bind(&Comparator::CompareData, ref(compare), _1, _2, _3, false)), ref(*pFile1) );

function<void()> task = [&](){ File::HashFile( bind(&Comparator::CompareData, ref(compare), _1, _2, _3, false), *pFile1 ); };

function<void()> task = [&](){ File::HashFile([&](const void *pv, size_t cb, const char *szDesc) { compare.CompareData(pv, cb, szDesc, false); }, *pFile1 ); };

 

(Random comment: The 170 lines of incomprehensible errors you get if you forget the static_cast<HashFn> on the first line is completely obnoxious.  [HashFn is a typedef for function<void(const void *, size_t, const char *)>])

 

The last one is the best

Lambdas supersede bind() 99% of the time - they are easier to read, easier to write, more efficient, and don't explode horribly.  The remaining 1% of cases are better handled by handwritten functors (e.g. with templated function call operators).

This is especially true now that 16.1/VC11's lambdas v1.1 handle nested lambdas just fine.  (In contrast, nested bind() is a bug farm, which has been tormenting me for years.)

 

I wish it was true…

         Lambdas aren’t polymorphic (and even when I write my own ad hoc function objects I prefer to make them stateless and just use bind for state)

         You do not have to specify the argument(s) type(s)

         IMHO, for simple bindings, bind is easier to read

         Bind has been around for so many years that, at least to me, it just come natural.

I completely agree about nested binds: understanding them is mindbending.

posted @ 2011-03-02 17:59 Enki 阅读(274) | 评论 (0)编辑 收藏

nullptr/__nullptr

 

MSDN has conflicting information about nullptr/__nullptr and /clr:

 

http://msdn.microsoft.com/en-us/library/dd465215(VS.100).aspx says:

The Visual C++ compiler lets you use the nullptr keyword with native code or with managed code. ... The compiler interprets nullptr to be managed code when you use the /clr compiler option, and native code when you do not use the /clr option.

 

Then adds:

The Microsoft-specific __nullptr keyword has the same meaning as nullptr, but it applies to native code only. If you compile native C/C++ code by using the /clr compiler option, the compiler cannot determine whether the nullptr keyword is a native or a managed term. To make your intention clear to the compiler, use the nullptr keyword to specify the managed term, and __nullptr to specify the native term.

 

Highlighted part indicates that compiler cannot determine whether it is native or managed, but the previous paragraph just said it will interpret it as managed.

 

http://msdn.microsoft.com/en-us/library/4ex65770.aspx says the same "cannot determine" thing and then gives an example to contrary:

 

The following sample shows that nullptr can be assigned to a native pointer when you compile with /clr.

// mcpp_nullptr_6.cpp
// compile with: /clr
int main() {
   int * i = 0;
   int * j = nullptr;
}
So what should I expect from all of this? I am guessing that the compiler takes nullptr as managed with /clr,
 because otherwise there wouldn't be a way to say nullptr in managed, and the sample is just an old garbage?
 
Here's how it's supposed to work, and what MSDN should say:
__nullptr is always the Native Nullptr, regardless of whether the compilation is native, /clr, or /clr:pure.
std::nullptr_t is always the Native Nullptr's Type, regardless of whether the compilation is native, /clr, or /clr:pure.  It is defined by <cstddef>.  For good measure (as permitted but not required by C++0x), both <cstddef> and <stddef.h> define both std::nullptr_t and ::nullptr_t.  JonCaves even made the compiler join the fun - it defines std::nullptr_t (but not ::nullptr_t) even in the absence of any headers whatsoever.
nullptr is the Native Nullptr when compiled as native (as required by C++0x).
nullptr is the Managed Nullptr Of Doom when compiled as /clr or /clr:pure (as required by the Necronomicon, 
which is to say C++/CLI).
That said, I don't know how the Managed Nullptr works, except that I've heard that "it doesn't have a type", 
a concept from which my mind recoils in fear.  There's been a little talk of unifying these things, 
but I don't think anybody has figured out what that would involve yet.  When this came up I said:
> Regarding A Tale Of Two Nullptrs, I've heard several times that the problem is that the managed nullptr 
"doesn't have a type", whatever that means, while the native nullptr has a type.  
I don't know what it'd take to unify them (I assume that the native nullptr would have to "win", 
since it cannot be infected with managedness, and conversions to managed stuff would have to be added to make 
up the difference - and too bad for anyone who inspects nullptr closely and is surprised to discover that it 
now has a type - I think all of those words in that order make sense), other than the fact that it 
wasn't obviously simple enough for JonCaves to do in the first place.
> The Iron Nullptr Curtain causes more user suffering than STL suffering, though - 
our only real interaction is in the definition of std::nullptr_t where we simply say decltype(__nullptr).  
In the rest of our implementation, we just use NULL/0 (Dinkumware overwhelmingly prefers 0, as I recall).
 

In this case, perhaps the ambiguity in the docs is a reflection of the thing itself. If nullptr is always
the MNOD when compiled with /clr, then why does the compiler allow int* j to be initialized with it,
as shown in the code example referred to below? I don’t know why the docs say “the compiler cannot determine…”
because at least in these simple initializations it seems to know what to do (converting nullptr to nullptr_t
when the lhs is a native type, regardless of /clr?). But I’m curious what pain this causes or might cause for users.
Is there ever a case where the non-identity of these two things leaks out? If so, then we should really mention that
in the docs.

 

// mcpp_nullptr_6.cpp
// compile with: /clr
int main() {
   int * i = 0;
   int * j = nullptr; //what IS j now?
   int^ k = nullptr; //the same or different?
}
 
 
 
 
 
 
 
 

C:\Temp>type doooooooom.cpp

#include <iostream>

#include <memory>

#include <ostream>

using namespace std;

 

int main() {

    auto sp = make_shared<int *>(nullptr);

    cout << sp.get() << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 doooooooom.cpp

doooooooom.cpp

 

C:\Temp>doooooooom

00227B2C

 

C:\Temp>cl /clr /nologo /W4 doooooooom.cpp

doooooooom.cpp

doooooooom.cpp(7) : error C2664: 'std::tr1::shared_ptr<_Ty> std::tr1::make_shared<int*,nullptr>(_Arg0 &&)' : cannot conv

ert parameter 1 from 'nullptr' to 'nullptr &&'

        with

        [

            _Ty=int *,

            _Arg0=nullptr

        ]

        nullptr can only be converted to pointer or handle types

doooooooom.cpp(7) : fatal error C1903: unable to recover from previous error(s); stopping compilation





















































posted @ 2011-03-02 17:58 Enki 阅读(1258) | 评论 (0)编辑 收藏

仅列出标题  下一页
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

导航

统计

常用链接

留言簿

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜